Add Joplin, old Mac, and Fedora WiFi runbooks; simplify JA3 Whisky scripts and hotspot recovery.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -81,6 +81,9 @@ Desktop.ini
|
|||||||
# *.tar.gz
|
# *.tar.gz
|
||||||
# *.rar
|
# *.rar
|
||||||
|
|
||||||
# --- Local overrides (keep repo-agnostic) ---
|
# --- old_mac local secrets ---
|
||||||
|
.config/old_mac/
|
||||||
|
docs/old_mac/.env
|
||||||
|
docs/old_mac/**/.env
|
||||||
*.local
|
*.local
|
||||||
*.local.*
|
*.local.*
|
||||||
|
|||||||
38
docs/apps/anytype/scripts/diagnose-phone-usb-mac.sh
Executable file
38
docs/apps/anytype/scripts/diagnose-phone-usb-mac.sh
Executable file
@@ -0,0 +1,38 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Диагностика: Mac не видит телефон по USB (заряжается, но нет data / USB-модема).
|
||||||
|
# Использование:
|
||||||
|
# ./docs/apps/anytype/scripts/diagnose-phone-usb-mac.sh
|
||||||
|
# ./docs/apps/anytype/scripts/diagnose-phone-usb-mac.sh watch # опрос каждые 2 с
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
watch="${1:-}"
|
||||||
|
|
||||||
|
scan() {
|
||||||
|
printf '\n=== %s ===\n' "$(date '+%H:%M:%S')"
|
||||||
|
echo "--- USB (iPhone / Android) ---"
|
||||||
|
if system_profiler SPUSBDataType 2>/dev/null | grep -qiE 'iPhone|iPad|Apple Mobile|Android|MTP|PTP|Vendor ID: 0x05ac|Vendor ID: 0x18d1|Vendor ID: 0x04e8|Vendor ID: 0x2717'; then
|
||||||
|
system_profiler SPUSBDataType 2>/dev/null | grep -B1 -A6 -iE 'iPhone|iPad|Apple Mobile|Android|MTP|PTP|Vendor ID: 0x05ac|Vendor ID: 0x18d1|Vendor ID: 0x04e8|Vendor ID: 0x2717'
|
||||||
|
else
|
||||||
|
echo "Телефон в USB-дереве НЕ найден (только зарядка или кабель/порт без data)."
|
||||||
|
fi
|
||||||
|
echo "--- usbmuxd (iPhone) ---"
|
||||||
|
pgrep -lf usbmuxd 2>/dev/null || echo "usbmuxd не запущен"
|
||||||
|
if command -v idevice_id >/dev/null 2>&1; then
|
||||||
|
echo "idevice_id -l: $(idevice_id -l 2>&1 || true)"
|
||||||
|
fi
|
||||||
|
echo "--- Сетевые интерфейсы (ожидаем iPhone USB / RNDIS) ---"
|
||||||
|
networksetup -listallnetworkservices 2>/dev/null | grep -iE 'iphone|usb|rndis|android' || echo "(службы USB-модема нет)"
|
||||||
|
echo "--- Совет ---"
|
||||||
|
echo "1) Кабель с передачей данных (не «только зарядка»)"
|
||||||
|
echo "2) Порт Mac напрямую, не через хаб (сейчас виден Genesys USB Hub)"
|
||||||
|
echo "3) iPhone: Разблокировать → «Доверять» → Настройки → Режим модема → USB"
|
||||||
|
echo "4) Android: USB → «Передача файлов» или «USB-модем»"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$watch" = "watch" ]; then
|
||||||
|
echo "Следим за USB. Переподключите телефон. Ctrl+C для выхода."
|
||||||
|
while true; do scan; sleep 2; done
|
||||||
|
else
|
||||||
|
scan
|
||||||
|
fi
|
||||||
84
docs/apps/joplin/README.md
Normal file
84
docs/apps/joplin/README.md
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
# Joplin — локальный синк Mac ↔ телефон (WebDAV, без Docker)
|
||||||
|
|
||||||
|
Синхронизация через **rclone WebDAV** только в локальной сети. Данные на Mac в `~/JoplinSync`. Облака Joplin/Dropbox не используются.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Быстрый старт (Mac)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
brew install rclone # если ещё нет
|
||||||
|
chmod +x ./docs/apps/joplin/scripts/joplin-webdav-*.sh
|
||||||
|
./docs/apps/joplin/scripts/joplin-webdav-install.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Показать URL и статус:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./docs/apps/joplin/scripts/joplin-webdav-status.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Учётка: `~/.config/joplin-webdav/env` (права `600`, **не коммитить**).
|
||||||
|
|
||||||
|
Остановка / запуск:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./docs/apps/joplin/scripts/joplin-webdav-stop.sh
|
||||||
|
./docs/apps/joplin/scripts/joplin-webdav-serve.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
**После смены пароля в `~/.config/joplin-webdav/env`** — обязательно перезапуск (иначе rclone держит старый пароль → **401**):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./docs/apps/joplin/scripts/joplin-webdav-reload.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Пароль в Joplin на телефоне и Mac должен **совпадать с `JOPLIN_WEBDAV_PASS` в env**, не со старым из установки.
|
||||||
|
|
||||||
|
Автозапуск при входе: LaunchAgent `com.eternal.joplin-webdav` (ставится install-скриптом).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Настройка Joplin (Mac и телефон)
|
||||||
|
|
||||||
|
1. **Настройки → Синхронизация**
|
||||||
|
2. Внизу: **Self-hosting → Click here to select one**
|
||||||
|
3. **WebDAV**
|
||||||
|
4. Заполнить:
|
||||||
|
|
||||||
|
| Поле | Значение |
|
||||||
|
|------|----------|
|
||||||
|
| WebDAV URL | **Mac:** `http://127.0.0.1:8080` · **Телефон:** `http://10.219.227.100:8080` (статический IP на Mac — [STABLE_SETUP](../../connectivity/apps/joplin/STABLE_SETUP.md)) |
|
||||||
|
| Логин | `joplin` |
|
||||||
|
| Пароль | из `~/.config/joplin-webdav/env` → `JOPLIN_WEBDAV_PASS` |
|
||||||
|
|
||||||
|
5. **Проверить конфигурацию синхронизации** → OK → синхронизировать.
|
||||||
|
|
||||||
|
**Важно:** Mac и телефон в **одной сети** (хотспот телефона). URL с `http://`, не `https://`. Без слэша в конце URL.
|
||||||
|
|
||||||
|
Опционально: **Настройки → Шифрование** — E2EE (мастер-пароль), на сервере только шифротекст.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Приватность
|
||||||
|
|
||||||
|
- Заметки на телефоне — в песочнице **Joplin**, не «доступ ко всем файлам».
|
||||||
|
- WebDAV слушает `0.0.0.0:8080` только пока запущен rclone; не открывайте порт в интернет.
|
||||||
|
- При включённом фаерволе macOS разрешите вход для **rclone** или порта **8080** в локальной сети.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Если не коннектится с телефона
|
||||||
|
|
||||||
|
1. `./docs/apps/joplin/scripts/joplin-webdav-status.sh` — процесс и IP.
|
||||||
|
2. На телефоне в браузере: `http://IP_MAC:8080` (может запросить логин — значит сеть доходит).
|
||||||
|
3. Синк сломался — [RUNBOOK](../../connectivity/apps/joplin/RUNBOOK.md); стабильная схема без смены URL — [STABLE_SETUP](../../connectivity/apps/joplin/STABLE_SETUP.md).
|
||||||
|
4. Логи: `~/Library/Logs/joplin-webdav/`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Связанное
|
||||||
|
|
||||||
|
- **[Runbook: синк сломался (хотспот, логи, ETIMEDOUT)](../../connectivity/apps/joplin/RUNBOOK.md)**
|
||||||
|
- [Anytype (P2P, без WebDAV)](../anytype/README.md)
|
||||||
|
- [diagnose-phone-usb-mac.sh](../anytype/scripts/diagnose-phone-usb-mac.sh) — если понадобится USB
|
||||||
31
docs/apps/joplin/scripts/joplin-android-hotspot-setup.sh
Executable file
31
docs/apps/joplin/scripts/joplin-android-hotspot-setup.sh
Executable file
@@ -0,0 +1,31 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Полная настройка Joplin для Android-хотспота (Mac = клиент Wi‑Fi).
|
||||||
|
# .local с телефона не работает → alias *.100 + LaunchAgent.
|
||||||
|
#
|
||||||
|
# ./joplin-android-hotspot-setup.sh install
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
ROOT="$(CDPATH= cd -- "$(dirname "$0")" && pwd)"
|
||||||
|
|
||||||
|
echo "=== Joplin: Android-хотспот (Mac клиент) ==="
|
||||||
|
echo ""
|
||||||
|
echo "Почему не eternals.local:"
|
||||||
|
echo " Android, раздающий хотспот, не резолвит .local имён подключённых устройств."
|
||||||
|
echo " rclone.log — только 127.0.0.1, запросов с телефона нет."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
"$ROOT/joplin-hotspot-alias-install.sh"
|
||||||
|
echo ""
|
||||||
|
echo "Поднимаем alias (sudo)..."
|
||||||
|
"$ROOT/joplin-hotspot-alias.sh" ensure
|
||||||
|
echo ""
|
||||||
|
"$ROOT/joplin-hotspot-alias.sh" status
|
||||||
|
echo ""
|
||||||
|
echo "=== На телефоне в Joplin WebDAV ==="
|
||||||
|
grep '^JOPLIN_PHONE_URL=' "${JOPLIN_WEBDAV_CONFIG:-$HOME/.config/joplin-webdav/env}" 2>/dev/null \
|
||||||
|
| cut -d= -f2- || phone_url=$("$ROOT/joplin-hotspot-alias.sh" status | awk '/URL на телефоне/{getline; print}' | tr -d ' ')
|
||||||
|
echo " $(grep '^JOPLIN_PHONE_URL=' "$HOME/.config/joplin-webdav/env" 2>/dev/null | cut -d= -f2-)"
|
||||||
|
echo ""
|
||||||
|
echo "При смене подсети (10.219→10.74) URL меняется — alias LaunchAgent поднимет *.100,"
|
||||||
|
echo "новый URL: ./joplin-hotspot-alias.sh status"
|
||||||
25
docs/apps/joplin/scripts/joplin-hotspot-alias-install-sudo.sh
Executable file
25
docs/apps/joplin/scripts/joplin-hotspot-alias-install-sudo.sh
Executable file
@@ -0,0 +1,25 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Одноразово: passwordless sudo только для joplin-hotspot-alias.sh ensure
|
||||||
|
set -e
|
||||||
|
|
||||||
|
SCRIPT="$(CDPATH= cd -- "$(dirname "$0")" && pwd)/joplin-hotspot-alias.sh"
|
||||||
|
DEST="/etc/sudoers.d/joplin-hotspot-alias"
|
||||||
|
USER_NAME="$(whoami)"
|
||||||
|
|
||||||
|
[ -x "$SCRIPT" ] || chmod +x "$SCRIPT"
|
||||||
|
|
||||||
|
TMP="$(mktemp)"
|
||||||
|
trap 'rm -f "$TMP"' EXIT
|
||||||
|
|
||||||
|
cat >"$TMP" <<EOF
|
||||||
|
# Joplin WebDAV: alias *.100 на en0 после reconnect хотспота (только этот скрипт)
|
||||||
|
${USER_NAME} ALL=(ALL) NOPASSWD: ${SCRIPT} ensure
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "Будет создан $DEST:"
|
||||||
|
cat "$TMP"
|
||||||
|
echo ""
|
||||||
|
sudo cp "$TMP" "$DEST"
|
||||||
|
sudo chmod 440 "$DEST"
|
||||||
|
sudo visudo -c -f "$DEST"
|
||||||
|
echo "OK. LaunchAgent сможет поднимать alias без пароля."
|
||||||
45
docs/apps/joplin/scripts/joplin-hotspot-alias-install.sh
Executable file
45
docs/apps/joplin/scripts/joplin-hotspot-alias-install.sh
Executable file
@@ -0,0 +1,45 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# LaunchAgent: каждые 60 с проверять alias *.100 (нужен joplin-hotspot-alias-install-sudo.sh).
|
||||||
|
set -e
|
||||||
|
|
||||||
|
ROOT="$(CDPATH= cd -- "$(dirname "$0")" && pwd)"
|
||||||
|
ALIAS="$ROOT/joplin-hotspot-alias.sh"
|
||||||
|
PLIST="$HOME/Library/LaunchAgents/com.eternal.joplin-hotspot-alias.plist"
|
||||||
|
|
||||||
|
chmod +x "$ROOT"/joplin-hotspot-alias*.sh
|
||||||
|
|
||||||
|
mkdir -p "$HOME/Library/LaunchAgents" "$HOME/Library/Logs/joplin-webdav"
|
||||||
|
|
||||||
|
cat >"$PLIST" <<EOF
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>Label</key>
|
||||||
|
<string>com.eternal.joplin-hotspot-alias</string>
|
||||||
|
<key>ProgramArguments</key>
|
||||||
|
<array>
|
||||||
|
<string>$ALIAS</string>
|
||||||
|
<string>ensure</string>
|
||||||
|
</array>
|
||||||
|
<key>StartInterval</key>
|
||||||
|
<integer>60</integer>
|
||||||
|
<key>RunAtLoad</key>
|
||||||
|
<true/>
|
||||||
|
<key>StandardOutPath</key>
|
||||||
|
<string>$HOME/Library/Logs/joplin-webdav/alias-launchd.out.log</string>
|
||||||
|
<key>StandardErrorPath</key>
|
||||||
|
<string>$HOME/Library/Logs/joplin-webdav/alias-launchd.err.log</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
EOF
|
||||||
|
|
||||||
|
launchctl bootout "gui/$(id -u)/com.eternal.joplin-hotspot-alias" 2>/dev/null || true
|
||||||
|
launchctl bootstrap "gui/$(id -u)" "$PLIST"
|
||||||
|
launchctl enable "gui/$(id -u)/com.eternal.joplin-hotspot-alias" 2>/dev/null || true
|
||||||
|
|
||||||
|
echo "LaunchAgent com.eternal.joplin-hotspot-alias установлен (каждые 60 с)."
|
||||||
|
echo "Для работы без пароля один раз:"
|
||||||
|
echo " $ROOT/joplin-hotspot-alias-install-sudo.sh"
|
||||||
|
echo "Сейчас:"
|
||||||
|
"$ALIAS" status
|
||||||
149
docs/apps/joplin/scripts/joplin-hotspot-alias.sh
Executable file
149
docs/apps/joplin/scripts/joplin-hotspot-alias.sh
Executable file
@@ -0,0 +1,149 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Стабильный URL для Joplin на телефоне при Android-хотспоте: http://<подсеть>.100:8080
|
||||||
|
# Alias *.100 на en0 (DHCP primary не трогаем). LaunchAgent поднимает alias после reconnect.
|
||||||
|
#
|
||||||
|
# ./joplin-hotspot-alias.sh status
|
||||||
|
# ./joplin-hotspot-alias.sh ensure
|
||||||
|
#
|
||||||
|
# Passwordless: ./joplin-hotspot-alias-install-sudo.sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
CONFIG="${JOPLIN_WEBDAV_CONFIG:-$HOME/.config/joplin-webdav/env}"
|
||||||
|
WIFI_DEV="${WIFI_DEVICE:-en0}"
|
||||||
|
PORT="${JOPLIN_WEBDAV_PORT:-8080}"
|
||||||
|
LOG="$HOME/Library/Logs/joplin-webdav/alias.log"
|
||||||
|
|
||||||
|
ipv4_subnet() {
|
||||||
|
printf '%s\n' "$1" | awk -F. '{print $1"."$2"."$3}'
|
||||||
|
}
|
||||||
|
|
||||||
|
ipv4_last_octet() {
|
||||||
|
printf '%s\n' "$1" | awk -F. '{print $4}'
|
||||||
|
}
|
||||||
|
|
||||||
|
default_gateway() {
|
||||||
|
route -n get default 2>/dev/null | awk '/gateway:/{print $2; exit}'
|
||||||
|
}
|
||||||
|
|
||||||
|
load_config() {
|
||||||
|
if [ -f "$CONFIG" ]; then
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
. "$CONFIG"
|
||||||
|
fi
|
||||||
|
PORT="${JOPLIN_WEBDAV_PORT:-$PORT}"
|
||||||
|
}
|
||||||
|
|
||||||
|
joplin_phone_ip() {
|
||||||
|
load_config
|
||||||
|
gw="$(default_gateway 2>/dev/null || true)"
|
||||||
|
[ -n "$gw" ] || return 1
|
||||||
|
subnet="$(ipv4_subnet "$gw")"
|
||||||
|
if [ -n "${JOPLIN_STATIC_IP:-}" ]; then
|
||||||
|
last="$(ipv4_last_octet "$JOPLIN_STATIC_IP")"
|
||||||
|
else
|
||||||
|
last=100
|
||||||
|
fi
|
||||||
|
printf '%s\n' "${subnet}.${last}"
|
||||||
|
}
|
||||||
|
|
||||||
|
phone_url() {
|
||||||
|
ip="$(joplin_phone_ip 2>/dev/null || true)"
|
||||||
|
[ -n "$ip" ] || return 1
|
||||||
|
printf 'http://%s:%s\n' "$ip" "$PORT"
|
||||||
|
}
|
||||||
|
|
||||||
|
has_ip_on_dev() {
|
||||||
|
ip="$1"
|
||||||
|
dev="$2"
|
||||||
|
ifconfig "$dev" 2>/dev/null | grep -q "inet ${ip} "
|
||||||
|
}
|
||||||
|
|
||||||
|
log_msg() {
|
||||||
|
mkdir -p "$(dirname "$LOG")"
|
||||||
|
printf '%s %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*" >>"$LOG"
|
||||||
|
}
|
||||||
|
|
||||||
|
run_priv() {
|
||||||
|
if [ "$(id -u)" -eq 0 ]; then
|
||||||
|
"$@"
|
||||||
|
else
|
||||||
|
sudo "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
write_phone_url_env() {
|
||||||
|
url="$(phone_url 2>/dev/null || true)"
|
||||||
|
[ -n "$url" ] && [ -f "$CONFIG" ] || return 0
|
||||||
|
if grep -q '^JOPLIN_PHONE_URL=' "$CONFIG" 2>/dev/null; then
|
||||||
|
sed -i '' "s|^JOPLIN_PHONE_URL=.*|JOPLIN_PHONE_URL=$url|" "$CONFIG" 2>/dev/null \
|
||||||
|
|| sed -i "s|^JOPLIN_PHONE_URL=.*|JOPLIN_PHONE_URL=$url|" "$CONFIG"
|
||||||
|
else
|
||||||
|
printf 'JOPLIN_PHONE_URL=%s\n' "$url" >>"$CONFIG"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_status() {
|
||||||
|
load_config
|
||||||
|
target="$(joplin_phone_ip 2>/dev/null || true)"
|
||||||
|
primary="$(ipconfig getifaddr "$WIFI_DEV" 2>/dev/null || true)"
|
||||||
|
gw="$(default_gateway 2>/dev/null || true)"
|
||||||
|
url="$(phone_url 2>/dev/null || true)"
|
||||||
|
|
||||||
|
echo "mode: Android-хотспот (alias *.100)"
|
||||||
|
echo "device: $WIFI_DEV"
|
||||||
|
echo "primary: ${primary:-(none)}"
|
||||||
|
echo "gateway: ${gw:-(none)}"
|
||||||
|
echo "joplin IP: ${target:-(no gateway)}"
|
||||||
|
|
||||||
|
if [ -n "$target" ] && has_ip_on_dev "$target" "$WIFI_DEV"; then
|
||||||
|
echo "alias: OK"
|
||||||
|
elif [ -n "$target" ] && [ "$primary" = "$target" ]; then
|
||||||
|
echo "alias: OK (primary)"
|
||||||
|
elif [ -n "$target" ]; then
|
||||||
|
echo "alias: MISSING — телефон не достучится"
|
||||||
|
echo " fix: $0 ensure"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$url" ]; then
|
||||||
|
echo ""
|
||||||
|
echo "URL на телефоне (работает с Android-хотспота):"
|
||||||
|
echo " $url"
|
||||||
|
echo ""
|
||||||
|
echo "⚠ http://*.local:8080 с телефона НЕ работает (Android не резолвит mDNS клиентов хотспота)"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_ensure() {
|
||||||
|
target="$(joplin_phone_ip 2>/dev/null || true)"
|
||||||
|
if [ -z "$target" ]; then
|
||||||
|
log_msg "skip: no gateway"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
primary="$(ipconfig getifaddr "$WIFI_DEV" 2>/dev/null || true)"
|
||||||
|
if [ -z "$primary" ]; then
|
||||||
|
log_msg "skip: no primary IP"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
if [ "$primary" = "$target" ] || has_ip_on_dev "$target" "$WIFI_DEV"; then
|
||||||
|
write_phone_url_env
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
log_msg "add alias $target on $WIFI_DEV (primary $primary)"
|
||||||
|
run_priv ifconfig "$WIFI_DEV" inet "$target" netmask 255.255.255.0 alias
|
||||||
|
write_phone_url_env
|
||||||
|
echo "alias OK: $target"
|
||||||
|
echo "URL на телефоне: $(phone_url)"
|
||||||
|
}
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo "Usage: $(basename "$0") status|ensure" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
case "${1:-ensure}" in
|
||||||
|
status) cmd_status ;;
|
||||||
|
ensure) cmd_ensure ;;
|
||||||
|
-h|--help) usage ;;
|
||||||
|
*) usage ;;
|
||||||
|
esac
|
||||||
165
docs/apps/joplin/scripts/joplin-mdns-setup.sh
Executable file
165
docs/apps/joplin/scripts/joplin-mdns-setup.sh
Executable file
@@ -0,0 +1,165 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Стабильный URL для Joplin на телефоне: http://<LocalHostName>.local:8080
|
||||||
|
# Не зависит от подсети хотспота (10.219.x → 10.74.x). Alias *.100 не нужен.
|
||||||
|
#
|
||||||
|
# ./joplin-mdns-setup.sh status
|
||||||
|
# ./joplin-mdns-setup.sh install # записать URL в env (rename опционально)
|
||||||
|
# ./joplin-mdns-setup.sh verify
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
CONFIG="${JOPLIN_WEBDAV_CONFIG:-$HOME/.config/joplin-webdav/env}"
|
||||||
|
PORT="${JOPLIN_WEBDAV_PORT:-8080}"
|
||||||
|
WIFI_DEV="${WIFI_DEVICE:-en0}"
|
||||||
|
# Пусто = текущий LocalHostName Mac (у вас часто Eternals → eternals.local)
|
||||||
|
PREFERRED_HOST="${JOPLIN_MDNS_HOST:-}"
|
||||||
|
|
||||||
|
load_config() {
|
||||||
|
if [ -f "$CONFIG" ]; then
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
. "$CONFIG"
|
||||||
|
fi
|
||||||
|
PORT="${JOPLIN_WEBDAV_PORT:-$PORT}"
|
||||||
|
PREFERRED_HOST="${JOPLIN_MDNS_HOST:-$PREFERRED_HOST}"
|
||||||
|
}
|
||||||
|
|
||||||
|
current_local_hostname() {
|
||||||
|
scutil --get LocalHostName 2>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
|
mdns_host() {
|
||||||
|
load_config
|
||||||
|
if [ -n "$PREFERRED_HOST" ]; then
|
||||||
|
printf '%s\n' "$PREFERRED_HOST"
|
||||||
|
else
|
||||||
|
current_local_hostname
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
mdns_fqdn() {
|
||||||
|
printf '%s.local\n' "$(mdns_host | tr '[:upper:]' '[:lower:]')"
|
||||||
|
}
|
||||||
|
|
||||||
|
phone_url() {
|
||||||
|
host="$(mdns_host | tr '[:upper:]' '[:lower:]')"
|
||||||
|
printf 'http://%s.local:%s\n' "$host" "$PORT"
|
||||||
|
}
|
||||||
|
|
||||||
|
primary_ip() {
|
||||||
|
ipconfig getifaddr "$WIFI_DEV" 2>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve_mdns_ip() {
|
||||||
|
host="$(mdns_fqdn)"
|
||||||
|
dscacheutil -q host -a name "$host" 2>/dev/null \
|
||||||
|
| awk '/ip_address:/ {print $2}' | grep -v '^127\.' | head -1
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_status() {
|
||||||
|
load_config
|
||||||
|
local_name="$(current_local_hostname)"
|
||||||
|
host="$(mdns_host)"
|
||||||
|
ip="$(primary_ip)"
|
||||||
|
resolved="$(resolve_mdns_ip 2>/dev/null || true)"
|
||||||
|
url="$(phone_url)"
|
||||||
|
|
||||||
|
echo "LocalHostName: ${local_name:-?}"
|
||||||
|
echo "mDNS host: $host → $(mdns_fqdn)"
|
||||||
|
echo "primary $WIFI_DEV: ${ip:-(none)}"
|
||||||
|
echo "mDNS → IP: ${resolved:-(none)}"
|
||||||
|
echo ""
|
||||||
|
echo "mDNS URL (НЕ для Android-хотспота — телефон не резолвит .local клиентов):"
|
||||||
|
echo " $url"
|
||||||
|
echo "URL на Mac: http://127.0.0.1:${PORT}"
|
||||||
|
echo "Телефон-хотспот: ./joplin-hotspot-alias.sh status"
|
||||||
|
|
||||||
|
if [ -n "$PREFERRED_HOST" ] && [ "$local_name" != "$PREFERRED_HOST" ]; then
|
||||||
|
echo ""
|
||||||
|
echo "⚠ В env JOPLIN_MDNS_HOST=$PREFERRED_HOST, LocalHostName=$local_name"
|
||||||
|
echo " install переименует Mac или уберите JOPLIN_MDNS_HOST из env"
|
||||||
|
elif [ -n "$ip" ] && [ -n "$resolved" ] && [ "$ip" = "$resolved" ]; then
|
||||||
|
echo ""
|
||||||
|
echo "OK: mDNS на Mac резолвится (для телефона используйте alias *.100)"
|
||||||
|
elif [ -n "$ip" ] && [ -z "$resolved" ]; then
|
||||||
|
echo ""
|
||||||
|
echo "⚠ mDNS пока не резолвится — подождите или переподключите Wi‑Fi"
|
||||||
|
elif [ -z "$ip" ]; then
|
||||||
|
echo ""
|
||||||
|
echo "⚠ Нет IP на $WIFI_DEV"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
write_env_mdns() {
|
||||||
|
load_config
|
||||||
|
url="$(phone_url)"
|
||||||
|
host="$(mdns_host)"
|
||||||
|
if [ ! -f "$CONFIG" ]; then
|
||||||
|
echo "Нет $CONFIG — сначала joplin-webdav-install.sh" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if grep -q '^JOPLIN_MDNS_HOST=' "$CONFIG" 2>/dev/null; then
|
||||||
|
sed -i '' "s|^JOPLIN_MDNS_HOST=.*|JOPLIN_MDNS_HOST=$host|" "$CONFIG" 2>/dev/null \
|
||||||
|
|| sed -i "s|^JOPLIN_MDNS_HOST=.*|JOPLIN_MDNS_HOST=$host|" "$CONFIG"
|
||||||
|
else
|
||||||
|
printf 'JOPLIN_MDNS_HOST=%s\n' "$host" >>"$CONFIG"
|
||||||
|
fi
|
||||||
|
if grep -q '^JOPLIN_PHONE_URL=' "$CONFIG" 2>/dev/null; then
|
||||||
|
sed -i '' "s|^JOPLIN_PHONE_URL=.*|JOPLIN_PHONE_URL=$url|" "$CONFIG" 2>/dev/null \
|
||||||
|
|| sed -i "s|^JOPLIN_PHONE_URL=.*|JOPLIN_PHONE_URL=$url|" "$CONFIG"
|
||||||
|
else
|
||||||
|
printf 'JOPLIN_PHONE_URL=%s\n' "$url" >>"$CONFIG"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_install() {
|
||||||
|
load_config
|
||||||
|
local_name="$(current_local_hostname)"
|
||||||
|
target="$(mdns_host)"
|
||||||
|
|
||||||
|
if [ -n "$PREFERRED_HOST" ] && [ "$local_name" != "$PREFERRED_HOST" ]; then
|
||||||
|
echo "Переименование LocalHostName: $local_name → $PREFERRED_HOST"
|
||||||
|
if [ "$(id -u)" -eq 0 ]; then
|
||||||
|
scutil --set LocalHostName "$PREFERRED_HOST"
|
||||||
|
else
|
||||||
|
sudo scutil --set LocalHostName "$PREFERRED_HOST"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Используем текущий LocalHostName: $local_name (→ $(mdns_fqdn))"
|
||||||
|
fi
|
||||||
|
|
||||||
|
write_env_mdns
|
||||||
|
echo ""
|
||||||
|
echo "На телефоне в Joplin WebDAV (один раз):"
|
||||||
|
echo " $(phone_url)"
|
||||||
|
echo ""
|
||||||
|
sleep 2
|
||||||
|
cmd_verify || true
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_verify() {
|
||||||
|
ip="$(primary_ip)"
|
||||||
|
resolved="$(resolve_mdns_ip 2>/dev/null || true)"
|
||||||
|
if [ -z "$ip" ]; then
|
||||||
|
echo "verify: нет IP на $WIFI_DEV" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ "$ip" = "$resolved" ]; then
|
||||||
|
echo "verify OK: $(mdns_fqdn) → $ip"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
echo "verify: mDNS=${resolved:-none} ip=$ip (часто OK через 30с после connect)" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo "Usage: $(basename "$0") status|install|verify" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
case "${1:-status}" in
|
||||||
|
status) cmd_status ;;
|
||||||
|
install) cmd_install ;;
|
||||||
|
verify) cmd_verify ;;
|
||||||
|
-h|--help) usage ;;
|
||||||
|
*) usage ;;
|
||||||
|
esac
|
||||||
90
docs/apps/joplin/scripts/joplin-webdav-install.sh
Executable file
90
docs/apps/joplin/scripts/joplin-webdav-install.sh
Executable file
@@ -0,0 +1,90 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Установка: конфиг, launchd (автозапуск), первый старт WebDAV.
|
||||||
|
set -e
|
||||||
|
|
||||||
|
ROOT="$(CDPATH= cd -- "$(dirname "$0")" && pwd)"
|
||||||
|
CONFIG_DIR="$HOME/.config/joplin-webdav"
|
||||||
|
CONFIG="$CONFIG_DIR/env"
|
||||||
|
LAUNCH_AGENT="$HOME/Library/LaunchAgents/com.eternal.joplin-webdav.plist"
|
||||||
|
SERVE="$ROOT/joplin-webdav-serve.sh"
|
||||||
|
|
||||||
|
mkdir -p "$CONFIG_DIR" "$HOME/JoplinSync" "$HOME/Library/Logs/joplin-webdav"
|
||||||
|
|
||||||
|
if [ ! -f "$CONFIG" ]; then
|
||||||
|
PASS=$(openssl rand -base64 18 | tr -d '/+=' | head -c 24)
|
||||||
|
cat > "$CONFIG" <<EOF
|
||||||
|
# Локальный WebDAV для Joplin. Только LAN. Не коммитить.
|
||||||
|
JOPLIN_WEBDAV_USER=joplin
|
||||||
|
JOPLIN_WEBDAV_PASS=$PASS
|
||||||
|
JOPLIN_WEBDAV_PORT=8080
|
||||||
|
JOPLIN_WEBDAV_ROOT=$HOME/JoplinSync
|
||||||
|
# Опционально (legacy alias *.100 — не нужен при mDNS):
|
||||||
|
# JOPLIN_STATIC_IP=10.219.227.100
|
||||||
|
# JOPLIN_MDNS_HOST=joplin-mac
|
||||||
|
# JOPLIN_PHONE_URL=http://joplin-mac.local:8080
|
||||||
|
EOF
|
||||||
|
chmod 600 "$CONFIG"
|
||||||
|
echo "Создан $CONFIG"
|
||||||
|
else
|
||||||
|
echo "Конфиг уже есть: $CONFIG"
|
||||||
|
fi
|
||||||
|
|
||||||
|
chmod +x "$ROOT"/joplin-webdav-*.sh
|
||||||
|
|
||||||
|
if ! command -v rclone >/dev/null 2>&1; then
|
||||||
|
echo "Устанавливаю rclone..."
|
||||||
|
brew install rclone
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$HOME/Library/LaunchAgents"
|
||||||
|
cat > "$LAUNCH_AGENT" <<EOF
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>Label</key>
|
||||||
|
<string>com.eternal.joplin-webdav</string>
|
||||||
|
<key>ProgramArguments</key>
|
||||||
|
<array>
|
||||||
|
<string>$SERVE</string>
|
||||||
|
<string>--foreground</string>
|
||||||
|
</array>
|
||||||
|
<key>RunAtLoad</key>
|
||||||
|
<true/>
|
||||||
|
<key>KeepAlive</key>
|
||||||
|
<true/>
|
||||||
|
<key>StandardOutPath</key>
|
||||||
|
<string>$HOME/Library/Logs/joplin-webdav/launchd.out.log</string>
|
||||||
|
<key>StandardErrorPath</key>
|
||||||
|
<string>$HOME/Library/Logs/joplin-webdav/launchd.err.log</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
EOF
|
||||||
|
|
||||||
|
launchctl bootout "gui/$(id -u)/com.eternal.joplin-webdav" 2>/dev/null || true
|
||||||
|
launchctl bootstrap "gui/$(id -u)" "$LAUNCH_AGENT"
|
||||||
|
launchctl enable "gui/$(id -u)/com.eternal.joplin-webdav" 2>/dev/null || true
|
||||||
|
|
||||||
|
launchctl enable "gui/$(id -u)/com.eternal.joplin-webdav" 2>/dev/null || true
|
||||||
|
|
||||||
|
chmod +x "$ROOT"/joplin-mdns-setup.sh 2>/dev/null || true
|
||||||
|
if [ -x "$ROOT/joplin-mdns-setup.sh" ]; then
|
||||||
|
echo ""
|
||||||
|
echo "=== mDNS (стабильный URL на телефоне) ==="
|
||||||
|
if [ "$(scutil --get LocalHostName 2>/dev/null)" = "joplin-mac" ]; then
|
||||||
|
"$ROOT/joplin-mdns-setup.sh" status || true
|
||||||
|
else
|
||||||
|
echo "LocalHostName ещё не joplin-mac. Один раз:"
|
||||||
|
echo " $ROOT/joplin-mdns-setup.sh install"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
sleep 2
|
||||||
|
"$ROOT/joplin-webdav-status.sh"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Пароль для Joplin:"
|
||||||
|
grep JOPLIN_WEBDAV_PASS "$CONFIG" | cut -d= -f2-
|
||||||
|
echo ""
|
||||||
|
echo "На телефоне (один раз, навсегда): http://joplin-mac.local:8080"
|
||||||
|
echo "Установка имени: $ROOT/joplin-mdns-setup.sh install"
|
||||||
7
docs/apps/joplin/scripts/joplin-webdav-reload.sh
Executable file
7
docs/apps/joplin/scripts/joplin-webdav-reload.sh
Executable file
@@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Перечитать ~/.config/joplin-webdav/env и перезапустить WebDAV (после смены пароля).
|
||||||
|
set -e
|
||||||
|
uid=$(id -u)
|
||||||
|
launchctl kickstart -k "gui/${uid}/com.eternal.joplin-webdav"
|
||||||
|
sleep 2
|
||||||
|
"$(dirname "$0")/joplin-webdav-status.sh"
|
||||||
72
docs/apps/joplin/scripts/joplin-webdav-serve.sh
Executable file
72
docs/apps/joplin/scripts/joplin-webdav-serve.sh
Executable file
@@ -0,0 +1,72 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Локальный WebDAV для синхронизации Joplin (Mac ↔ телефон по LAN).
|
||||||
|
# Данные: ~/JoplinSync. Учётка: ~/.config/joplin-webdav/env
|
||||||
|
#
|
||||||
|
# ./joplin-webdav-serve.sh # фон
|
||||||
|
# ./joplin-webdav-serve.sh --foreground # передний план (для launchd)
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
CONFIG="${JOPLIN_WEBDAV_CONFIG:-$HOME/.config/joplin-webdav/env}"
|
||||||
|
LOG_DIR="$HOME/Library/Logs/joplin-webdav"
|
||||||
|
PID_FILE="$HOME/.config/joplin-webdav/rclone.pid"
|
||||||
|
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname "$0")" && pwd)
|
||||||
|
|
||||||
|
mkdir -p "$LOG_DIR" "$(dirname "$PID_FILE")"
|
||||||
|
|
||||||
|
if [ ! -f "$CONFIG" ]; then
|
||||||
|
echo "Нет $CONFIG — запустите: $SCRIPT_DIR/joplin-webdav-install.sh" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
. "$CONFIG"
|
||||||
|
|
||||||
|
: "${JOPLIN_WEBDAV_USER:?}"
|
||||||
|
: "${JOPLIN_WEBDAV_PASS:?}"
|
||||||
|
: "${JOPLIN_WEBDAV_PORT:=8080}"
|
||||||
|
: "${JOPLIN_WEBDAV_ROOT:=$HOME/JoplinSync}"
|
||||||
|
|
||||||
|
mkdir -p "$JOPLIN_WEBDAV_ROOT"
|
||||||
|
|
||||||
|
RCLONE="$(command -v rclone || echo /opt/homebrew/bin/rclone)"
|
||||||
|
if [ ! -x "$RCLONE" ]; then
|
||||||
|
echo "rclone не найден. Установите: brew install rclone" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
run_rclone() {
|
||||||
|
exec "$RCLONE" serve webdav "$JOPLIN_WEBDAV_ROOT" \
|
||||||
|
--addr "0.0.0.0:${JOPLIN_WEBDAV_PORT}" \
|
||||||
|
--user "$JOPLIN_WEBDAV_USER" \
|
||||||
|
--pass "$JOPLIN_WEBDAV_PASS" \
|
||||||
|
--vfs-cache-mode minimal \
|
||||||
|
--log-file "$LOG_DIR/rclone.log" \
|
||||||
|
--log-level INFO
|
||||||
|
}
|
||||||
|
|
||||||
|
case "${1:-}" in
|
||||||
|
--foreground|-f)
|
||||||
|
run_rclone
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [ -f "$PID_FILE" ]; then
|
||||||
|
old_pid=$(cat "$PID_FILE")
|
||||||
|
if kill -0 "$old_pid" 2>/dev/null; then
|
||||||
|
echo "Уже запущен (PID $old_pid), порт ${JOPLIN_WEBDAV_PORT}"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
rm -f "$PID_FILE"
|
||||||
|
fi
|
||||||
|
nohup "$0" --foreground >>"$LOG_DIR/stdout.log" 2>&1 &
|
||||||
|
echo $! >"$PID_FILE"
|
||||||
|
sleep 1
|
||||||
|
if kill -0 "$(cat "$PID_FILE")" 2>/dev/null; then
|
||||||
|
echo "WebDAV запущен (PID $(cat "$PID_FILE")), порт ${JOPLIN_WEBDAV_PORT}"
|
||||||
|
else
|
||||||
|
echo "Не удалось запустить. См. $LOG_DIR/stdout.log" >&2
|
||||||
|
rm -f "$PID_FILE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
73
docs/apps/joplin/scripts/joplin-webdav-status.sh
Executable file
73
docs/apps/joplin/scripts/joplin-webdav-status.sh
Executable file
@@ -0,0 +1,73 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
CONFIG="${JOPLIN_WEBDAV_CONFIG:-$HOME/.config/joplin-webdav/env}"
|
||||||
|
PID_FILE="$HOME/.config/joplin-webdav/rclone.pid"
|
||||||
|
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname "$0")" && pwd)
|
||||||
|
|
||||||
|
echo "=== WebDAV Joplin ==="
|
||||||
|
if [ -f "$CONFIG" ]; then
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
. "$CONFIG"
|
||||||
|
echo "Пользователь: ${JOPLIN_WEBDAV_USER:-?}"
|
||||||
|
echo "Порт: ${JOPLIN_WEBDAV_PORT:-8080}"
|
||||||
|
echo "Папка: ${JOPLIN_WEBDAV_ROOT:-$HOME/JoplinSync}"
|
||||||
|
else
|
||||||
|
echo "Конфиг не найден: $CONFIG"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Процесс ==="
|
||||||
|
if pgrep -f "rclone serve webdav" >/dev/null 2>&1; then
|
||||||
|
pgrep -lf "rclone serve webdav" 2>/dev/null || true
|
||||||
|
else
|
||||||
|
echo "Не запущен → ./docs/apps/joplin/scripts/joplin-webdav-serve.sh"
|
||||||
|
fi
|
||||||
|
|
||||||
|
port="${JOPLIN_WEBDAV_PORT:-8080}"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== URL для телефона (Android-хотспот) ==="
|
||||||
|
if [ -x "$SCRIPT_DIR/joplin-hotspot-alias.sh" ]; then
|
||||||
|
"$SCRIPT_DIR/joplin-hotspot-alias.sh" status
|
||||||
|
else
|
||||||
|
echo "(нет joplin-hotspot-alias.sh)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== mDNS (.local) — с телефона НЕ работает ==="
|
||||||
|
if [ -x "$SCRIPT_DIR/joplin-mdns-setup.sh" ]; then
|
||||||
|
host="$(scutil --get LocalHostName 2>/dev/null | tr '[:upper:]' '[:lower:]' || echo '?')"
|
||||||
|
echo "http://${host}.local:${port} — только Mac/Windows; Android-хотспот не резолвит"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== IP Mac (DHCP, справочно) ==="
|
||||||
|
ip=$(ipconfig getifaddr en0 2>/dev/null || true)
|
||||||
|
[ -n "$ip" ] && echo "primary en0: $ip" || echo "нет IP"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Порт :8080 ==="
|
||||||
|
lsof -nP -iTCP:"$port" -sTCP:LISTEN 2>/dev/null || echo "не слушает"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== URL в Joplin (Mac) ==="
|
||||||
|
settings="$HOME/.config/joplin-desktop/settings.json"
|
||||||
|
if [ -f "$settings" ]; then
|
||||||
|
grep -o '"sync\.6\.path": *"[^"]*"' "$settings" 2>/dev/null | sed 's/.*"\(http[^"]*\)".*/\1/' \
|
||||||
|
| while read -r u; do echo "settings.json: $u"; done
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== rclone (запросы с телефона?) ==="
|
||||||
|
log="$HOME/Library/Logs/joplin-webdav/rclone.log"
|
||||||
|
if [ -f "$log" ]; then
|
||||||
|
phone_lines=$(grep -E 'from 10\.|from 192\.168\.' "$log" 2>/dev/null | tail -3)
|
||||||
|
if [ -n "$phone_lines" ]; then
|
||||||
|
echo "$phone_lines"
|
||||||
|
else
|
||||||
|
echo "нет запросов с LAN (только 127.0.0.1?) — телефон не достучался"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Учётка ==="
|
||||||
|
[ -f "$CONFIG" ] && echo "Пароль: $CONFIG → JOPLIN_WEBDAV_PASS"
|
||||||
18
docs/apps/joplin/scripts/joplin-webdav-stop.sh
Executable file
18
docs/apps/joplin/scripts/joplin-webdav-stop.sh
Executable file
@@ -0,0 +1,18 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
PID_FILE="$HOME/.config/joplin-webdav/rclone.pid"
|
||||||
|
|
||||||
|
if [ ! -f "$PID_FILE" ]; then
|
||||||
|
echo "WebDAV не запущен (нет $PID_FILE)"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
pid=$(cat "$PID_FILE")
|
||||||
|
if kill -0 "$pid" 2>/dev/null; then
|
||||||
|
kill "$pid" 2>/dev/null || true
|
||||||
|
sleep 1
|
||||||
|
kill -9 "$pid" 2>/dev/null || true
|
||||||
|
echo "Остановлен (PID $pid)"
|
||||||
|
else
|
||||||
|
echo "Процесс $pid уже не работает"
|
||||||
|
fi
|
||||||
|
rm -f "$PID_FILE"
|
||||||
@@ -1,111 +1,110 @@
|
|||||||
# Emergency: сеть после смены хотспота (macOS)
|
# Emergency: сеть после переподключения хотспота (macOS)
|
||||||
|
|
||||||
Симптом: **отключили Mac от Wi‑Fi / переподключились к другому хотспоту — «интернета нет», помогает только перезагрузка.**
|
|
||||||
|
|
||||||
Документ описывает **проверенную на машине причину** в вашей конфигурации, **ручное восстановление без перезагрузки** и **скрипт** из репозитория.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Причина (точная по конфигурации)
|
## Одна команда (из любой папки)
|
||||||
|
|
||||||
На macOS в **Системных настройках → Сеть → Wi‑Fi → Подробнее → Прокси** часто включён **автоматический прокси (PAC)** с URL вида **`http://localhost:1089/proxy.pac`** (см. [PROXY_GUIDE.md](./PROXY_GUIDE.md) → раздел про системный PAC).
|
```bash
|
||||||
|
bash /Users/eternal/code/local_machine/docs/connectivity/scripts/macos-hotspot-network-recover.sh recover
|
||||||
|
```
|
||||||
|
|
||||||
Проверка на рабочей машине (2026): **PAC для сервиса Wi‑Fi включён (Enabled: Yes)**, при этом **на порту 1089 нет процесса**, который отдаёт `proxy.pac` — соединение к `127.0.0.1:1089` отклоняется.
|
Запросит **пароль sudo**, затем: PAC/SOCKS off → **DHCP** → `ifconfig down` → **`route -n flush`** → DNS → DHCP → **Joplin alias `*.100`**.
|
||||||
|
|
||||||
В таком состоянии:
|
Диагностика:
|
||||||
|
|
||||||
1. Система и часть приложений **сначала** должны получить PAC с localhost; при недоступном URL поведение **нестабильно** (часть трафика «в никуда», таймауты).
|
```bash
|
||||||
2. При **смене хотспота** меняются шлюз, DNS, часто появляется **captive portal**; страница входа может **не открыться**, пока PAC мешает или DNS закеширован со старой сети.
|
bash /Users/eternal/code/local_machine/docs/connectivity/scripts/macos-hotspot-network-recover.sh status
|
||||||
3. **Перезагрузка** «лечит», потому что заново поднимаются **configd**, **mDNSResponder**, порядок инициализации Wi‑Fi и иногда снова стартует локальный PAC‑сервер (Clash / Surge / свой сервис на 1089).
|
```
|
||||||
|
|
||||||
Дополнительные усилители сбоя (проверять при `status`):
|
|
||||||
|
|
||||||
- **Системный SOCKS** на `127.0.0.1:1080` (Shadowsocks и т.д.) — если включён, а клиент не слушает порт, трафик через системный прокси тоже падает.
|
|
||||||
- **VPN / туннели** с политикой «весь трафик» — после смены сети маршруты могут остаться битые до отключения VPN.
|
|
||||||
|
|
||||||
**SOCKS Telegram (1081) и SSH‑туннели сами по себе не отключают Wi‑Fi** — они приложенческие. Проблема класса «всё мёртво до ребута» у вас с высокой вероятностью — **системный PAC/SOCKS на localhost без живого сервиса + кэш DNS / состояние Wi‑Fi**.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Быстро: один скрипт (рекомендуется)
|
## RCA (почему старый `recover` не помогал)
|
||||||
|
|
||||||
Из корня репозитория `local_machine`:
|
### 1. Ядерный сброс не выполнялся
|
||||||
|
|
||||||
```bash
|
Скрипт проверял `sudo -n` (passwordless). Без NOPASSWD в sudoers он **пропускал** `route flush` и делал только toggle Wi‑Fi — **недостаточно** при ARP `REJECT`.
|
||||||
chmod +x ./docs/connectivity/scripts/macos-hotspot-network-recover.sh
|
|
||||||
./docs/connectivity/scripts/macos-hotspot-network-recover.sh status
|
Ручная «ядерная кнопка» работала, потому что вы вводили пароль и реально сбрасывали маршруты.
|
||||||
./docs/connectivity/scripts/macos-hotspot-network-recover.sh recover
|
|
||||||
|
**Исправлено:** `recover` всегда вызывает `sudo` с запросом пароля.
|
||||||
|
|
||||||
|
### 2. Manual IPv4 на Wi‑Fi (Joplin) ломал маршрут
|
||||||
|
|
||||||
|
`/var/log/wifi.log` при reconnect:
|
||||||
|
|
||||||
|
```
|
||||||
|
IP Address: 10.219.227.100
|
||||||
|
Default Gateway IP Address: 10.219.227.39
|
||||||
|
No Router MAC Address
|
||||||
|
ROUTER_MAC_ADDR = 0x000000000000
|
||||||
```
|
```
|
||||||
|
|
||||||
`recover` делает: **выключает PAC** (те же сервисы, что и `macos-system-pac.sh`), **выключает системный SOCKS на Wi‑Fi**, по возможности **сбрасывает DNS** и **кратко перезапускает Wi‑Fi** и DHCP.
|
В prefs оставался шлюз `10.219.227.39`, хотспот уже в `10.36.136.x` → `ping` → `Host is down`, `curl` мёртв.
|
||||||
|
|
||||||
Если скрипт пишет, что нет `sudo` без пароля — выполните вручную команды из раздела «Вручную» ниже.
|
**Исправлено:** Wi‑Fi **только DHCP**; Joplin — **alias** `<подсеть>.100` на `en0` (не трогает default route). См. [apps/joplin/STABLE_SETUP.md](./apps/joplin/STABLE_SETUP.md).
|
||||||
|
|
||||||
После появления интернета, если вам снова нужен PAC:
|
### 3. PAC / SOCKS (вторично)
|
||||||
|
|
||||||
```bash
|
PAC на `:1089` без сервера усиливает сбои, но **не объясняет** `ping 8.8.8.8 → No route to host`.
|
||||||
./docs/connectivity/scripts/macos-pac-on.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
Только **после** того как процесс на **1089** реально запущен и отдаёт `proxy.pac`.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Вручную (без скрипта)
|
## Что делает `recover` сейчас
|
||||||
|
|
||||||
### 1. Отключить автоматический PAC
|
| Шаг | Действие |
|
||||||
|
|-----|----------|
|
||||||
|
| 1 | PAC off |
|
||||||
|
| 2 | SOCKS off |
|
||||||
|
| 3 | `networksetup -setdhcp Wi-Fi` (снимает Manual) |
|
||||||
|
| 4 | `sudo ifconfig en0 down` |
|
||||||
|
| 5 | `sudo route -n flush` |
|
||||||
|
| 6 | DNS flush + `ifconfig up` + `ipconfig DHCP` |
|
||||||
|
| 7 | Ждёт gateway (до 30 с) |
|
||||||
|
| 8 | `ifconfig en0 alias <subnet>.100` для Joplin |
|
||||||
|
|
||||||
**GUI:** Системные настройки → Сеть → Wi‑Fi → Подробнее → Прокси → снять **«Автоматическая настройка прокси (PAC)»**.
|
---
|
||||||
|
|
||||||
**CLI** (из репо):
|
## Ядерная кнопка (если скрипт недоступен)
|
||||||
|
|
||||||
```bash
|
|
||||||
./docs/connectivity/scripts/macos-pac-off.sh
|
|
||||||
./docs/connectivity/scripts/macos-system-pac.sh status
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Отключить системный SOCKS (если включали для Shadowsocks)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
networksetup -setsocksfirewallproxystate "Wi-Fi" off
|
|
||||||
networksetup -getsocksfirewallproxy "Wi-Fi"
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. Сброс DNS
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
sudo networksetup -setdhcp "Wi-Fi"
|
||||||
|
sudo ifconfig en0 down
|
||||||
|
sudo route -n flush
|
||||||
sudo dscacheutil -flushcache
|
sudo dscacheutil -flushcache
|
||||||
sudo killall -HUP mDNSResponder
|
sudo killall -HUP mDNSResponder
|
||||||
```
|
sudo ifconfig en0 up
|
||||||
|
|
||||||
### 4. Обновить DHCP и «пнуть» Wi‑Fi
|
|
||||||
|
|
||||||
Узнать интерфейс Wi‑Fi (часто `en0`):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
networksetup -listallhardwareports | sed -n '/Hardware Port: Wi-Fi/,/Ethernet Address/p'
|
|
||||||
```
|
|
||||||
|
|
||||||
Дальше (подставьте свой `Device`, например `en0`):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo ipconfig set en0 DHCP
|
sudo ipconfig set en0 DHCP
|
||||||
networksetup -setairportpower en0 off
|
bash /Users/eternal/code/local_machine/docs/connectivity/scripts/macos-hotspot-network-recover.sh recover
|
||||||
sleep 2
|
|
||||||
networksetup -setairportpower en0 on
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 5. Captive portal
|
|
||||||
|
|
||||||
Откройте в браузере **`http://captive.apple.com`** или **`http://neverssl.com`** — должна открыться страница входа в сеть отели/кафе.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Профилактика (архитектурно)
|
## Диагностика
|
||||||
|
|
||||||
1. **Не держать PAC включённым**, если сервис на **1089** не запущен: сначала поднять Clash/Surge/свой HTTP‑сервер с PAC, **затем** `macos-pac-on.sh`.
|
```bash
|
||||||
2. Перед подключением к **чужому хотспоту** с обязательной страницей входа — **временно PAC off** (`macos-pac-off.sh`), залогиниться в сеть, затем при необходимости снова **on**.
|
networksetup -getinfo "Wi-Fi"
|
||||||
3. Разнести роли: **глобальный PAC** — только когда стабильно есть локальный конфиг‑сервер; для «чистого» интернета в дороге — **PAC выключен**, прокси только в приложениях (Telegram SOCKS **1081**, Cursor **10809** и т.д.) — см. [TELEGRAM_GUIDE.md](./TELEGRAM_GUIDE.md), [PROXY_EMERGENCY.md](./PROXY_EMERGENCY.md).
|
ifconfig en0 | grep inet
|
||||||
|
route -n get default
|
||||||
|
bash /Users/eternal/code/local_machine/docs/connectivity/scripts/macos-hotspot-network-recover.sh status
|
||||||
|
./docs/apps/joplin/scripts/joplin-webdav-status.sh
|
||||||
|
grep -E 'Router MAC|No Router' /var/log/wifi.log | tail -5
|
||||||
|
```
|
||||||
|
|
||||||
|
| Признак | Причина |
|
||||||
|
|---------|---------|
|
||||||
|
| Manual + другая подсеть в gateway | Старый Joplin static |
|
||||||
|
| `No Router MAC` в wifi.log | ARP на шлюз не прошёл |
|
||||||
|
| `REJECT` в route get gateway | Нужен route flush |
|
||||||
|
| Primary DHCP OK, нет `*.100` alias | Запустить `recover` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Профилактика
|
||||||
|
|
||||||
|
1. **Не** использовать Manual Wi‑Fi для Joplin — только DHCP + alias.
|
||||||
|
2. После **каждого** reconnect: одна команда `recover` выше.
|
||||||
|
3. PAC on — только если на **1089** слушает сервер.
|
||||||
|
4. `exit-via-ru-do.sh` — **после** рабочего `curl https://1.1.1.1`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -113,10 +112,6 @@ networksetup -setairportpower en0 on
|
|||||||
|
|
||||||
| Документ | Зачем |
|
| Документ | Зачем |
|
||||||
|----------|--------|
|
|----------|--------|
|
||||||
| [PROXY_GUIDE.md](./PROXY_GUIDE.md) | Системный PAC, порты, скрипты `macos-pac-*.sh` |
|
| [apps/joplin/STABLE_SETUP.md](./apps/joplin/STABLE_SETUP.md) | DHCP + alias |
|
||||||
| [PROXY_EMERGENCY.md](./PROXY_EMERGENCY.md) | SSH, SOCKS 1081, прод |
|
| [PROXY_EMERGENCY.md](./PROXY_EMERGENCY.md) | SSH / SOCKS |
|
||||||
| [README.md](./README.md) | Оглавление `connectivity/` |
|
| [README.md](./README.md) | Оглавление |
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*Если после `recover` сеть всё ещё мёртвая — проверьте аппаратный тумблер Wi‑Fi, другое SSID, и логи: Консоль → `Wi-Fi` / `configd`.*
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Одна страница на случай, когда «всё слетело». Полная схема, безопасность и нюансы `~/.ssh/config`: [PROXY_GUIDE.md](./PROXY_GUIDE.md).
|
Одна страница на случай, когда «всё слетело». Полная схема, безопасность и нюансы `~/.ssh/config`: [PROXY_GUIDE.md](./PROXY_GUIDE.md).
|
||||||
|
|
||||||
**Сеть / хотспот (интернет есть только после перезагрузки):** чаще всего системный **PAC на localhost:1089** без живого сервера или системный SOCKS на **1080**. Пошагово: **[HOTSPOT_NETWORK_EMERGENCY.md](./HOTSPOT_NETWORK_EMERGENCY.md)**.
|
**Сеть / хотспот (интернет есть только после перезагрузки):** чаще всего **Manual IPv4 на Wi‑Fi (Joplin)** при смене подсети Android + битые маршруты; также PAC **1089** / SOCKS **1080** без клиента. Пошагово: **[HOTSPOT_NETWORK_EMERGENCY.md](./HOTSPOT_NETWORK_EMERGENCY.md)**.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,9 @@
|
|||||||
| **[BUILD_AAB_FROM_RUSSIA_GUIDE.md](./BUILD_AAB_FROM_RUSSIA_GUIDE.md)** | Сборка AAB/APK из России: Maven proxy на проде + SSH-туннель |
|
| **[BUILD_AAB_FROM_RUSSIA_GUIDE.md](./BUILD_AAB_FROM_RUSSIA_GUIDE.md)** | Сборка AAB/APK из России: Maven proxy на проде + SSH-туннель |
|
||||||
| **[WINDOWS_CURSOR_TUNNEL.md](./WINDOWS_CURSOR_TUNNEL.md)** | Cursor из РФ на **Windows**: туннель через прокси, скрипт .ps1, автозапуск |
|
| **[WINDOWS_CURSOR_TUNNEL.md](./WINDOWS_CURSOR_TUNNEL.md)** | Cursor из РФ на **Windows**: туннель через прокси, скрипт .ps1, автозапуск |
|
||||||
| **[WINDOWS_SSH_KEY_INSTALL.md](./WINDOWS_SSH_KEY_INSTALL.md)** | Установка SSH-ключа на Windows (один файл `setup-ssh-key-for-proxy.ps1`, только для туннеля) |
|
| **[WINDOWS_SSH_KEY_INSTALL.md](./WINDOWS_SSH_KEY_INSTALL.md)** | Установка SSH-ключа на Windows (один файл `setup-ssh-key-for-proxy.ps1`, только для туннеля) |
|
||||||
| **[HOTSPOT_NETWORK_EMERGENCY.md](./HOTSPOT_NETWORK_EMERGENCY.md)** | Сеть после смены хотспота: причина (PAC localhost), ручной сброс без ребута, `macos-hotspot-network-recover.sh` |
|
| **[HOTSPOT_NETWORK_EMERGENCY.md](./HOTSPOT_NETWORK_EMERGENCY.md)** | Сеть после reconnect хотспота: Joplin Manual IP + смена подсети Android, route flush, PAC; `macos-hotspot-network-recover.sh` |
|
||||||
|
| **[apps/joplin/STABLE_SETUP.md](./apps/joplin/STABLE_SETUP.md)** | Joplin: стабильный URL на телефоне (статический IP Mac на Android-хотспоте) |
|
||||||
|
| **[apps/joplin/RUNBOOK.md](./apps/joplin/RUNBOOK.md)** | Joplin Mac ↔ телефон: диагностика, ETIMEDOUT/401, логи |
|
||||||
| **[scripts/](./scripts/)** | Скрипты для туннелей и локальной работы |
|
| **[scripts/](./scripts/)** | Скрипты для туннелей и локальной работы |
|
||||||
| **[launchd/](./launchd/)** | LaunchAgent для macOS: автозапуск SOCKS-туннеля при входе |
|
| **[launchd/](./launchd/)** | LaunchAgent для macOS: автозапуск SOCKS-туннеля при входе |
|
||||||
|
|
||||||
@@ -28,6 +30,7 @@
|
|||||||
- **Загрузка файлов на прод через прокси** — [PROXY_GUIDE.md → Загрузка файлов на прод (scp)](./PROXY_GUIDE.md#-загрузка-файлов-на-прод-через-туннель-scp)
|
- **Загрузка файлов на прод через прокси** — [PROXY_GUIDE.md → Загрузка файлов на прод (scp)](./PROXY_GUIDE.md#-загрузка-файлов-на-прод-через-туннель-scp)
|
||||||
- **Безопасность прокси (nginx, fail2ban)** — [PROXY_GUIDE.md → Безопасность](./PROXY_GUIDE.md#-безопасность), SECURITY.md (если есть в папке)
|
- **Безопасность прокси (nginx, fail2ban)** — [PROXY_GUIDE.md → Безопасность](./PROXY_GUIDE.md#-безопасность), SECURITY.md (если есть в папке)
|
||||||
- **Сборка AAB из РФ** — [BUILD_AAB_FROM_RUSSIA_GUIDE.md](./BUILD_AAB_FROM_RUSSIA_GUIDE.md)
|
- **Сборка AAB из РФ** — [BUILD_AAB_FROM_RUSSIA_GUIDE.md](./BUILD_AAB_FROM_RUSSIA_GUIDE.md)
|
||||||
|
- **Joplin: синк Mac ↔ телефон** — настройка [apps/joplin/STABLE_SETUP.md](./apps/joplin/STABLE_SETUP.md), поломки [apps/joplin/RUNBOOK.md](./apps/joplin/RUNBOOK.md), `./docs/apps/joplin/scripts/joplin-webdav-status.sh`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -36,7 +39,7 @@
|
|||||||
| Скрипт | Описание |
|
| Скрипт | Описание |
|
||||||
|--------|----------|
|
|--------|----------|
|
||||||
| **telegram-socks-tunnel.sh** | SOCKS5 на 1081 для Telegram. `TELEGRAM_SOCKS_VIA_DO=1` — только Mac→RU→DO (`telegram-socks-via-do`); без RU — ошибка. См. PROXY_GUIDE. |
|
| **telegram-socks-tunnel.sh** | SOCKS5 на 1081 для Telegram. `TELEGRAM_SOCKS_VIA_DO=1` — только Mac→RU→DO (`telegram-socks-via-do`); без RU — ошибка. См. PROXY_GUIDE. |
|
||||||
| **macos-hotspot-network-recover.sh** | После смены хотспота: `status` / `recover` (PAC off, SOCKS off на Wi‑Fi, DNS, DHCP, перезапуск радио). См. HOTSPOT_NETWORK_EMERGENCY.md. |
|
| **macos-hotspot-network-recover.sh** | Reconnect хотспота: `bash …/macos-hotspot-network-recover.sh recover` — DHCP, route flush (sudo), Joplin alias `*.100`. См. HOTSPOT_NETWORK_EMERGENCY.md. |
|
||||||
| **ssh-hunab-prod.sh** | Опционально: сначала `hunab-prod-direct`, иначе `hunab-prod` (в конфиге по умолчанию уже через RU). См. PROXY_GUIDE. |
|
| **ssh-hunab-prod.sh** | Опционально: сначала `hunab-prod-direct`, иначе `hunab-prod` (в конфиге по умолчанию уже через RU). См. PROXY_GUIDE. |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
23
docs/connectivity/apps/joplin/README.md
Normal file
23
docs/connectivity/apps/joplin/README.md
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Joplin (локальный синк Mac ↔ телефон)
|
||||||
|
|
||||||
|
WebDAV через rclone на Mac, Android-хотспот.
|
||||||
|
|
||||||
|
| Документ | Назначение |
|
||||||
|
|----------|------------|
|
||||||
|
| **[STABLE_SETUP.md](./STABLE_SETUP.md)** | Рабочая схема: alias `*.100` |
|
||||||
|
| **[RUNBOOK.md](./RUNBOOK.md)** | Синк сломался |
|
||||||
|
| [docs/apps/joplin/scripts/](../../../apps/joplin/scripts/) | Скрипты |
|
||||||
|
|
||||||
|
## URL (Android-хотспот)
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| Mac | `http://127.0.0.1:8080` |
|
||||||
|
| Телефон | `http://<подсеть>.100:8080` (см. `joplin-hotspot-alias.sh status`) |
|
||||||
|
|
||||||
|
**Не** `http://*.local:8080` — с телефона-хотспота не работает.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./docs/apps/joplin/scripts/joplin-webdav-status.sh
|
||||||
|
./docs/apps/joplin/scripts/joplin-hotspot-alias.sh status
|
||||||
|
```
|
||||||
263
docs/connectivity/apps/joplin/RUNBOOK.md
Normal file
263
docs/connectivity/apps/joplin/RUNBOOK.md
Normal file
@@ -0,0 +1,263 @@
|
|||||||
|
# Runbook: Joplin — синк Mac ↔ телефон (WebDAV / Android-хотспот)
|
||||||
|
|
||||||
|
Симптом: **синхронизация перестала работать** между Joplin на Mac и на телефоне.
|
||||||
|
|
||||||
|
Стек: **rclone serve webdav** на Mac → `~/JoplinSync` → Joplin (Mac + Android) по HTTP. Облако Joplin не используется.
|
||||||
|
|
||||||
|
**Рабочая схема (2026-06, проверено):** Mac на **DHCP**, alias **`*.100`** на `en0`, телефон → `http://<подсеть>.100:8080`. Подробно: [STABLE_SETUP.md](./STABLE_SETUP.md).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Архитектура
|
||||||
|
|
||||||
|
```
|
||||||
|
Телефон (Joplin) ──HTTP──► Mac en0 alias *.100:8080 ──► rclone ──► ~/JoplinSync/
|
||||||
|
Mac (Joplin) ──HTTP──► 127.0.0.1:8080 (тот же rclone)
|
||||||
|
```
|
||||||
|
|
||||||
|
| Компонент | Путь / имя |
|
||||||
|
|-----------|------------|
|
||||||
|
| Данные | `~/JoplinSync` |
|
||||||
|
| Учётка | `~/.config/joplin-webdav/env` (`600`, не в git) |
|
||||||
|
| WebDAV | LaunchAgent `com.eternal.joplin-webdav` |
|
||||||
|
| Alias `*.100` | LaunchAgent `com.eternal.joplin-hotspot-alias` (опционально + sudoers) |
|
||||||
|
| Лог rclone | `~/Library/Logs/joplin-webdav/rclone.log` |
|
||||||
|
| Лог alias | `~/Library/Logs/joplin-webdav/alias.log` |
|
||||||
|
| Лог Joplin Mac | `~/.config/joplin-desktop/log.txt` |
|
||||||
|
| Настройки Mac | `~/.config/joplin-desktop/settings.json` → `sync.6.path` |
|
||||||
|
|
||||||
|
Скрипты: `docs/apps/joplin/scripts/`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Шаг 0: диагностика
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./docs/apps/joplin/scripts/joplin-webdav-status.sh
|
||||||
|
./docs/apps/joplin/scripts/joplin-hotspot-alias.sh status
|
||||||
|
```
|
||||||
|
|
||||||
|
| Что смотреть | OK | Проблема |
|
||||||
|
|--------------|-----|----------|
|
||||||
|
| rclone / `:8080` | процесс слушает | `joplin-webdav-serve.sh` или `joplin-webdav-install.sh` |
|
||||||
|
| `alias: OK` | `*.100` на en0 | `joplin-hotspot-alias.sh ensure` (sudo) |
|
||||||
|
| rclone.log | `from 10.` или `from 192.` | только `127.0.0.1` — телефон не достучался |
|
||||||
|
| Mac URL | `127.0.0.1:8080` | настроить WebDAV на Mac |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Правильные URL
|
||||||
|
|
||||||
|
### Android раздаёт хотспот, Mac — клиент Wi‑Fi (основной сценарий)
|
||||||
|
|
||||||
|
| Устройство | WebDAV URL |
|
||||||
|
|------------|------------|
|
||||||
|
| **Mac** | `http://127.0.0.1:8080` |
|
||||||
|
| **Телефон** | `http://<подсеть>.100:8080` — сейчас часто `http://10.74.21.100:8080` |
|
||||||
|
|
||||||
|
Узнать актуальный URL:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./docs/apps/joplin/scripts/joplin-hotspot-alias.sh status
|
||||||
|
# или
|
||||||
|
grep JOPLIN_PHONE_URL ~/.config/joplin-webdav/env
|
||||||
|
```
|
||||||
|
|
||||||
|
**Не использовать на телефоне:**
|
||||||
|
|
||||||
|
| URL | Почему |
|
||||||
|
|-----|--------|
|
||||||
|
| `http://eternals.local:8080` | Android-хотспот **не резолвит** `.local` клиентов; в rclone.log нет запросов с телефона |
|
||||||
|
| `http://10.219.227.100:8080` | старая подсеть, если хотспот уже выдал `10.74.x` |
|
||||||
|
| `http://10.x.x.84:8080` (primary DHCP) | IP меняется при reconnect |
|
||||||
|
|
||||||
|
### Общее для Joplin
|
||||||
|
|
||||||
|
- Логин: `joplin`
|
||||||
|
- Пароль: `JOPLIN_WEBDAV_PASS` из env
|
||||||
|
- **Без** `/` в конце URL
|
||||||
|
- **Без пробела** в конце
|
||||||
|
- `http://`, не `https://`
|
||||||
|
- **Настройки → Синхронизация → Self-hosting → WebDAV** (не «Прокси»)
|
||||||
|
|
||||||
|
После смены URL на Mac: **Quit Joplin** → открыть снова → **Синхронизировать**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Симптом → причина → действие
|
||||||
|
|
||||||
|
### 1. «Синк OK, заметок нет на Mac»
|
||||||
|
|
||||||
|
Mac Joplin не на WebDAV — в `~/JoplinSync` только данные с телефона.
|
||||||
|
|
||||||
|
→ URL `http://127.0.0.1:8080`, проверить конфигурацию, синк.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. `ETIMEDOUT` / `connect ETIMEDOUT 10.x.x.x:8080`
|
||||||
|
|
||||||
|
**Причина:** на телефоне **устаревший IP** (другая подсеть или нет alias `.100`).
|
||||||
|
|
||||||
|
**Признаки:** Joplin `ETIMEDOUT`; rclone — нет свежих `GET`/`PUT` с `10.`.
|
||||||
|
|
||||||
|
**Действие:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./docs/apps/joplin/scripts/joplin-hotspot-alias.sh ensure # sudo
|
||||||
|
./docs/apps/joplin/scripts/joplin-hotspot-alias.sh status # новый URL
|
||||||
|
```
|
||||||
|
|
||||||
|
→ Обновить URL на телефоне **только если сменилась подсеть** (`10.219` → `10.74`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. `401 Unauthorized`
|
||||||
|
|
||||||
|
Пароль в Joplin ≠ env, или rclone не перезапущен.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
grep JOPLIN_WEBDAV_PASS ~/.config/joplin-webdav/env
|
||||||
|
./docs/apps/joplin/scripts/joplin-webdav-reload.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4. `Not a valid URL: …/info.json`
|
||||||
|
|
||||||
|
Пробел в конце URL в настройках Joplin → переписать URL.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 5. Порт 8080 не слушает
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./docs/apps/joplin/scripts/joplin-webdav-status.sh
|
||||||
|
./docs/apps/joplin/scripts/joplin-webdav-serve.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Лог: `~/Library/Logs/joplin-webdav/launchd.err.log`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 6. `ECONNREFUSED` / телефон «не достаёт», Mac — да
|
||||||
|
|
||||||
|
**Причина:** alias **`*.100` отсутствует** на `en0` (слетел после reconnect).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ifconfig en0 | grep inet
|
||||||
|
./docs/apps/joplin/scripts/joplin-hotspot-alias.sh status
|
||||||
|
curl -s -o /dev/null -w '%{http_code}\n' http://10.74.21.100:8080/ # подставьте *.100 из status
|
||||||
|
```
|
||||||
|
|
||||||
|
→ `joplin-hotspot-alias.sh ensure`
|
||||||
|
→ В браузере **на телефоне**: `http://<subnet>.100:8080` — запрос логина
|
||||||
|
→ Нет интернета на Mac: [HOTSPOT_NETWORK_EMERGENCY.md](../../HOTSPOT_NETWORK_EMERGENCY.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 7. `eternals.local` / `*.local` не работает с телефона
|
||||||
|
|
||||||
|
**Ожидаемо.** mDNS на Mac резолвится, Android-хотспот — нет. Использовать **`http://<subnet>.100:8080`**, не `.local`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Процедура: переподключили хотспот / сменили Wi‑Fi
|
||||||
|
|
||||||
|
### 1. Интернет на Mac
|
||||||
|
|
||||||
|
Если `curl` / браузер мёртвы:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash /Users/eternal/code/local_machine/docs/connectivity/scripts/macos-hotspot-network-recover.sh recover
|
||||||
|
```
|
||||||
|
|
||||||
|
Wi‑Fi должен быть **DHCP**, не Manual ([HOTSPOT_NETWORK_EMERGENCY.md](../../HOTSPOT_NETWORK_EMERGENCY.md)).
|
||||||
|
|
||||||
|
### 2. Joplin
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./docs/apps/joplin/scripts/joplin-webdav-status.sh
|
||||||
|
./docs/apps/joplin/scripts/joplin-hotspot-alias.sh ensure # если alias MISSING
|
||||||
|
```
|
||||||
|
|
||||||
|
Чеклист:
|
||||||
|
|
||||||
|
- [ ] rclone слушает `:8080`
|
||||||
|
- [ ] `alias: OK` (или `ensure` выполнен)
|
||||||
|
- [ ] **Mac:** `http://127.0.0.1:8080` — без изменений
|
||||||
|
- [ ] **Телефон:** URL из `status` — **не менять**, если подсеть та же (`10.74.21.x`)
|
||||||
|
- [ ] Подсеть **сменилась** → один раз новый `http://<new-subnet>.100:8080`
|
||||||
|
- [ ] В rclone.log появились `from 10.` после синка на телефоне
|
||||||
|
|
||||||
|
### 3. Авто-alias (рекомендуется один раз)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash ./docs/apps/joplin/scripts/joplin-android-hotspot-setup.sh install
|
||||||
|
bash ./docs/apps/joplin/scripts/joplin-hotspot-alias-install-sudo.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
LaunchAgent поднимает `*.100` каждые 60 с после reconnect.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Скрипты
|
||||||
|
|
||||||
|
| Скрипт | Когда |
|
||||||
|
|--------|--------|
|
||||||
|
| `joplin-webdav-status.sh` | Первая диагностика |
|
||||||
|
| `joplin-hotspot-alias.sh status\|ensure` | URL телефона, поднять alias |
|
||||||
|
| `joplin-android-hotspot-setup.sh install` | Полная настройка хотспота |
|
||||||
|
| `joplin-hotspot-alias-install-sudo.sh` | Alias без пароля (LaunchAgent) |
|
||||||
|
| `joplin-webdav-install.sh` | Первая установка rclone + launchd |
|
||||||
|
| `joplin-webdav-reload.sh` | После смены пароля в env |
|
||||||
|
| `joplin-mdns-setup.sh` | Справочно; **не для URL на телефоне-хотспоте** |
|
||||||
|
|
||||||
|
Путь: `docs/apps/joplin/scripts/`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Логи
|
||||||
|
|
||||||
|
**rclone.log** — успех: `PROPFIND`, `GET`, `PUT from <IP>`. Телефон часто виден как IP **шлюза** (`10.74.21.61`), не IP Mac — нормально для Android.
|
||||||
|
|
||||||
|
**log.txt Mac:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
grep -E 'Synchronizer: \[error\]|ETIMEDOUT|ECONNREFUSED|Unauthorized|Not a valid URL' \
|
||||||
|
~/.config/joplin-desktop/log.txt | tail -20
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Безопасность
|
||||||
|
|
||||||
|
- WebDAV только в LAN (`0.0.0.0:8080` пока rclone работает); не пробрасывать в интернет.
|
||||||
|
- env и пароль — не в git.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Связанные документы
|
||||||
|
|
||||||
|
| Документ | Зачем |
|
||||||
|
|----------|--------|
|
||||||
|
| [STABLE_SETUP.md](./STABLE_SETUP.md) | Схема alias `*.100`, установка |
|
||||||
|
| [README.md](./README.md) | Оглавление |
|
||||||
|
| [docs/apps/joplin/README.md](../../../apps/joplin/README.md) | Установка с нуля |
|
||||||
|
| [HOTSPOT_NETWORK_EMERGENCY.md](../../HOTSPOT_NETWORK_EMERGENCY.md) | Сеть macOS после reconnect |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## История инцидентов
|
||||||
|
|
||||||
|
| Дата | Симптом | Корень | Фикс |
|
||||||
|
|------|---------|--------|------|
|
||||||
|
| 2026-06-02 | 401 | Пароль env ≠ Joplin | `joplin-webdav-reload.sh` |
|
||||||
|
| 2026-06-08 | ETIMEDOUT | Старый IP на телефоне | Обновить URL |
|
||||||
|
| 2026-06-09 | Телефон не достаёт `.100` | Mac без alias | `joplin-hotspot-alias ensure` |
|
||||||
|
| 2026-06-15 | Нет интернета после reconnect | Manual Wi‑Fi + битые маршруты | `macos-hotspot-network-recover.sh recover`, DHCP |
|
||||||
|
| 2026-06-19 | `eternals.local` не работает | Android-хотспот не резолвит mDNS клиентов | URL `http://10.74.21.100:8080` + alias |
|
||||||
|
| 2026-06-19 | Синк OK | alias `.100` + LaunchAgent | [STABLE_SETUP.md](./STABLE_SETUP.md) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Актуальный URL телефона: `./docs/apps/joplin/scripts/joplin-hotspot-alias.sh status`.*
|
||||||
55
docs/connectivity/apps/joplin/STABLE_SETUP.md
Normal file
55
docs/connectivity/apps/joplin/STABLE_SETUP.md
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
# Стабильная настройка: Android-хотспот + Mac + Joplin
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Важно: `.local` с телефона **не работает**
|
||||||
|
|
||||||
|
`http://eternals.local:8080` резолвится на **Mac**, но **Android, раздающий хотспот, не умеет** резолвить `.local` имён **подключённых** клиентов (Mac). Запросы до rclone не доходят.
|
||||||
|
|
||||||
|
**Рабочая схема:** alias **`*.100`** на `en0` + URL `http://<подсеть>.100:8080`.
|
||||||
|
|
||||||
|
| Устройство | URL |
|
||||||
|
|------------|-----|
|
||||||
|
| Mac | `http://127.0.0.1:8080` |
|
||||||
|
| Телефон | `http://10.74.21.100:8080` (подсеть меняется → см. ниже) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Установка (один раз)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./docs/apps/joplin/scripts/joplin-webdav-install.sh
|
||||||
|
bash ./docs/apps/joplin/scripts/joplin-android-hotspot-setup.sh install
|
||||||
|
```
|
||||||
|
|
||||||
|
На телефоне — URL из вывода (`joplin-hotspot-alias.sh status`).
|
||||||
|
|
||||||
|
Автоподнятие alias после reconnect:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./docs/apps/joplin/scripts/joplin-hotspot-alias-install-sudo.sh # sudoers, без пароля
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## После reconnect
|
||||||
|
|
||||||
|
1. Alias поднимается LaunchAgent (если sudoers установлен)
|
||||||
|
2. Проверка: `./docs/apps/joplin/scripts/joplin-webdav-status.sh`
|
||||||
|
3. Если подсеть **та же** (`10.74.21.x`) — URL на телефоне **не менять**
|
||||||
|
4. Если подсеть **сменилась** (`10.219` → `10.74`) — **один раз** новый URL из `status`
|
||||||
|
|
||||||
|
Интернет пропал: `bash .../macos-hotspot-network-recover.sh recover`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Почему URL иногда меняется
|
||||||
|
|
||||||
|
Android выдаёт **разные подсети** (`10.219.227.x`, `10.74.21.x`). Без Tailscale/VPN **нельзя** иметь один HTTP-URL при любой подсети с телефона-хотспота. Фиксированный **хвост `.100`** + автоподнятие alias минимизируют ручную работу.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Связанное
|
||||||
|
|
||||||
|
- [RUNBOOK.md](./RUNBOOK.md)
|
||||||
|
- [HOTSPOT_NETWORK_EMERGENCY.md](../../HOTSPOT_NETWORK_EMERGENCY.md)
|
||||||
@@ -1,32 +1,244 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# Сброс сетевого стека macOS после смены хотспота / «интернет не поднимается без перезагрузки».
|
# Сброс сети после переподключения Android-хотспота (macOS).
|
||||||
# Типичная причина в связке с docs/connectivity: системный PAC на localhost:1089 при мёртвом/ещё не
|
|
||||||
# поднятом PAC-сервере + кэш DNS / Wi‑Fi. См. HOTSPOT_NETWORK_EMERGENCY.md
|
|
||||||
#
|
#
|
||||||
# Использование (из корня репозитория):
|
# RCA (почему старый recover не помогал):
|
||||||
# ./docs/connectivity/scripts/macos-hotspot-network-recover.sh status
|
# - Ядерный сброс (route flush, ifconfig down) выполнялся только при sudo -n (passwordless).
|
||||||
# ./docs/connectivity/scripts/macos-hotspot-network-recover.sh recover
|
# - Без NOPASSWD в sudoers скрипт делал лишь toggle Wi‑Fi — ARP REJECT и битые маршруты оставались.
|
||||||
|
# - Manual IPv4 на Wi‑Fi (Joplin 10.219.227.100) конфликтует с новой подсетью хотспота (10.36.x).
|
||||||
|
#
|
||||||
|
# Решение:
|
||||||
|
# - Wi‑Fi всегда DHCP (правильный шлюз после reconnect).
|
||||||
|
# - Joplin: вторичный IP (alias) *.100 в текущей подсети — не трогает default route.
|
||||||
|
# - recover всегда запрашивает sudo (пароль) для полного сброса.
|
||||||
|
#
|
||||||
|
# Из любой папки (одна команда, чинит интернет + Joplin alias):
|
||||||
|
# bash /Users/eternal/code/local_machine/docs/connectivity/scripts/macos-hotspot-network-recover.sh recover
|
||||||
#
|
#
|
||||||
# Переменные:
|
# Переменные:
|
||||||
# MACOS_PAC_SERVICES — как в macos-system-pac.sh (по умолчанию Wi-Fi|Thunderbolt Bridge 2)
|
# HOTSPOT_JOPLIN_MODE=alias|manual|off alias (по умолчанию при ~/.config/joplin-webdav/env), manual, off
|
||||||
# WIFI_DEVICE — например en0; иначе авто: первый Device у Hardware Port: Wi-Fi
|
# HOTSPOT_RECOVER_SKIP_JOPLIN=1 не трогать Joplin alias
|
||||||
|
# JOPLIN_STATIC_IP последний октет .100 из env; подсеть — текущая
|
||||||
|
# MACOS_PAC_SERVICES, WIFI_DEVICE
|
||||||
|
|
||||||
set -e
|
|
||||||
ROOT="$(cd "$(dirname "$0")" && pwd)"
|
ROOT="$(cd "$(dirname "$0")" && pwd)"
|
||||||
PAC_SCRIPT="$ROOT/macos-system-pac.sh"
|
PAC_SCRIPT="$ROOT/macos-system-pac.sh"
|
||||||
|
JOPLIN_ENV="${JOPLIN_WEBDAV_CONFIG:-$HOME/.config/joplin-webdav/env}"
|
||||||
|
JOPLIN_ALIAS_SCRIPT="${JOPLIN_ALIAS_SCRIPT:-$(cd "$ROOT/../../apps/joplin/scripts" 2>/dev/null && pwd)/joplin-hotspot-alias.sh}"
|
||||||
|
SCRIPT_SELF="$ROOT/$(basename "$0")"
|
||||||
|
|
||||||
wifi_device() {
|
wifi_device() {
|
||||||
if [ -n "${WIFI_DEVICE:-}" ]; then
|
if [ -n "${WIFI_DEVICE:-}" ]; then
|
||||||
printf '%s\n' "$WIFI_DEVICE"
|
printf '%s\n' "$WIFI_DEVICE"
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
# "Device: en0" под блоком "Hardware Port: Wi-Fi"
|
|
||||||
networksetup -listallhardwareports 2>/dev/null \
|
networksetup -listallhardwareports 2>/dev/null \
|
||||||
| awk '/Hardware Port: Wi-Fi$/ {p=1; next} p && /^Device: / {print $2; exit}'
|
| awk '/Hardware Port: Wi-Fi$/ {p=1; next} p && /^Device: / {print $2; exit}'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ipv4_subnet() {
|
||||||
|
printf '%s\n' "$1" | awk -F. '{print $1"."$2"."$3}'
|
||||||
|
}
|
||||||
|
|
||||||
|
ipv4_last_octet() {
|
||||||
|
printf '%s\n' "$1" | awk -F. '{print $4}'
|
||||||
|
}
|
||||||
|
|
||||||
|
load_joplin_env() {
|
||||||
|
if [ -f "$JOPLIN_ENV" ]; then
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
. "$JOPLIN_ENV"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
wifi_config_method() {
|
||||||
|
networksetup -getinfo "Wi-Fi" 2>/dev/null | awk 'NR==1 {print $1; exit}'
|
||||||
|
}
|
||||||
|
|
||||||
|
wifi_manual_router() {
|
||||||
|
networksetup -getinfo "Wi-Fi" 2>/dev/null | awk -F': ' '/^Router: / {print $2; exit}'
|
||||||
|
}
|
||||||
|
|
||||||
|
wifi_manual_ip() {
|
||||||
|
networksetup -getinfo "Wi-Fi" 2>/dev/null | awk -F': ' '/^IP address: / {print $2; exit}'
|
||||||
|
}
|
||||||
|
|
||||||
|
default_gateway() {
|
||||||
|
route -n get default 2>/dev/null | awk '/gateway:/{print $2; exit}'
|
||||||
|
}
|
||||||
|
|
||||||
|
joplin_mode() {
|
||||||
|
if [ "${HOTSPOT_RECOVER_SKIP_JOPLIN:-0}" = "1" ]; then
|
||||||
|
echo off
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
if [ -n "${HOTSPOT_JOPLIN_MODE:-}" ]; then
|
||||||
|
echo "$HOTSPOT_JOPLIN_MODE"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
# mDNS (joplin-mac.local) — URL на телефоне не зависит от подсети; alias не нужен
|
||||||
|
echo off
|
||||||
|
}
|
||||||
|
|
||||||
|
joplin_target_ip() {
|
||||||
|
load_joplin_env
|
||||||
|
gw="$(default_gateway 2>/dev/null || true)"
|
||||||
|
[ -n "$gw" ] || return 1
|
||||||
|
subnet="$(ipv4_subnet "$gw")"
|
||||||
|
if [ -n "${JOPLIN_STATIC_IP:-}" ]; then
|
||||||
|
last="$(ipv4_last_octet "$JOPLIN_STATIC_IP")"
|
||||||
|
else
|
||||||
|
last=100
|
||||||
|
fi
|
||||||
|
printf '%s\n' "${subnet}.${last}"
|
||||||
|
}
|
||||||
|
|
||||||
|
list_en0_alias_ips() {
|
||||||
|
dev="${1:-en0}"
|
||||||
|
ifconfig "$dev" 2>/dev/null | awk '/inet / && /alias/ {print $2}'
|
||||||
|
}
|
||||||
|
|
||||||
|
sudo_run() {
|
||||||
|
echo " \$ sudo $*"
|
||||||
|
sudo "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_dhcp_wifi() {
|
||||||
|
method="$(wifi_config_method 2>/dev/null || true)"
|
||||||
|
if [ "$method" = "Manual" ]; then
|
||||||
|
echo " Wi‑Fi Manual $(wifi_manual_ip) → $(wifi_manual_router) — переводим на DHCP..."
|
||||||
|
networksetup -setdhcp "Wi-Fi" 2>/dev/null || sudo_run networksetup -setdhcp "Wi-Fi"
|
||||||
|
else
|
||||||
|
echo " Wi‑Fi уже DHCP (или не Manual)."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
nuclear_network_reset() {
|
||||||
|
dev="$1"
|
||||||
|
echo " Ядерный сброс на $dev (нужен пароль sudo)..."
|
||||||
|
sudo_run ifconfig "$dev" down
|
||||||
|
sudo_run route -n flush
|
||||||
|
sudo_run dscacheutil -flushcache
|
||||||
|
sudo_run killall -HUP mDNSResponder
|
||||||
|
sudo_run ifconfig "$dev" up
|
||||||
|
sudo_run ipconfig set "$dev" DHCP
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_for_connectivity() {
|
||||||
|
dev="$1"
|
||||||
|
i=0
|
||||||
|
while [ "$i" -lt 30 ]; do
|
||||||
|
gw="$(default_gateway 2>/dev/null || true)"
|
||||||
|
ip="$(ipconfig getifaddr "$dev" 2>/dev/null || true)"
|
||||||
|
if [ -n "$gw" ] && [ -n "$ip" ]; then
|
||||||
|
if ping -c 1 -W 1500 "$gw" >/dev/null 2>&1; then
|
||||||
|
echo " Связность OK: IP=$ip gateway=$gw (${i}s)"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
i=$((i + 1))
|
||||||
|
done
|
||||||
|
echo " WARN: gateway/IP не поднялись за 30с — проверьте captive portal" >&2
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
remove_joplin_aliases() {
|
||||||
|
dev="$1"
|
||||||
|
target="$2"
|
||||||
|
for ip in $(list_en0_alias_ips "$dev"); do
|
||||||
|
case "$ip" in
|
||||||
|
*.*.*.100|"$target")
|
||||||
|
echo " Удаляем alias $ip на $dev"
|
||||||
|
sudo_run ifconfig "$dev" inet "$ip" -alias 2>/dev/null || true
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_joplin_alias() {
|
||||||
|
dev="$1"
|
||||||
|
target="$(joplin_target_ip 2>/dev/null || true)"
|
||||||
|
[ -n "$target" ] || { echo " Joplin alias: нет gateway" >&2; return 1; }
|
||||||
|
primary="$(ipconfig getifaddr "$dev" 2>/dev/null || true)"
|
||||||
|
if [ "$primary" = "$target" ]; then
|
||||||
|
echo " Joplin: primary IP уже $target"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
remove_joplin_aliases "$dev" "$target"
|
||||||
|
if ifconfig "$dev" 2>/dev/null | grep -q "inet $target "; then
|
||||||
|
echo " Joplin alias $target уже на $dev"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
echo " Joplin alias: $target/24 на $dev (primary DHCP: ${primary:-?})"
|
||||||
|
sudo_run ifconfig "$dev" inet "$target" netmask 255.255.255.0 alias
|
||||||
|
echo " URL на телефоне: http://${target}:8080"
|
||||||
|
if [ -f "$JOPLIN_ENV" ] && [ -n "${JOPLIN_STATIC_IP:-}" ]; then
|
||||||
|
cur_sub="$(ipv4_subnet "$target")"
|
||||||
|
env_sub="$(ipv4_subnet "$JOPLIN_STATIC_IP")"
|
||||||
|
if [ "$cur_sub" != "$env_sub" ]; then
|
||||||
|
echo " ⚠ Подсеть сменилась ($env_sub.x → $cur_sub.x) — обновите URL в Joplin на телефоне"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_joplin_manual() {
|
||||||
|
gw="$(default_gateway 2>/dev/null || true)"
|
||||||
|
[ -n "$gw" ] || return 1
|
||||||
|
target="$(joplin_target_ip 2>/dev/null || true)"
|
||||||
|
echo " Joplin manual (legacy): $target → router $gw"
|
||||||
|
networksetup -setmanual "Wi-Fi" "$target" 255.255.255.0 "$gw"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_manual_ipv4_status() {
|
||||||
|
info="$(networksetup -getinfo "Wi-Fi" 2>/dev/null || true)"
|
||||||
|
echo "$info" | head -5
|
||||||
|
method="$(printf '%s\n' "$info" | awk 'NR==1 {print $1; exit}')"
|
||||||
|
dev="$(wifi_device 2>/dev/null || echo en0)"
|
||||||
|
current_ip="$(ipconfig getifaddr "$dev" 2>/dev/null || true)"
|
||||||
|
gw="$(default_gateway 2>/dev/null || true)"
|
||||||
|
echo "--- runtime $dev ---"
|
||||||
|
echo "primary IP: ${current_ip:-(none)}"
|
||||||
|
echo "default gateway: ${gw:-(none)}"
|
||||||
|
aliases="$(list_en0_alias_ips "$dev" | tr '\n' ' ')"
|
||||||
|
if [ -n "$aliases" ]; then
|
||||||
|
echo "aliases: $aliases"
|
||||||
|
fi
|
||||||
|
if [ -f "$JOPLIN_ENV" ]; then
|
||||||
|
target="$(joplin_target_ip 2>/dev/null || true)"
|
||||||
|
echo "joplin target: ${target:-?} (mode: $(joplin_mode))"
|
||||||
|
if [ -n "$target" ] && ! ifconfig "$dev" 2>/dev/null | grep -q "inet $target "; then
|
||||||
|
echo "⚠ Joplin IP $target не на интерфейсе — телефон не достучится"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [ "$method" = "Manual" ]; then
|
||||||
|
manual_ip="$(printf '%s\n' "$info" | awk -F': ' '/^IP address: / {print $2; exit}')"
|
||||||
|
manual_router="$(printf '%s\n' "$info" | awk -F': ' '/^Router: / {print $2; exit}')"
|
||||||
|
if [ -n "$manual_router" ] && [ -n "$gw" ]; then
|
||||||
|
if [ "$(ipv4_subnet "$manual_router")" != "$(ipv4_subnet "$gw")" ]; then
|
||||||
|
echo "⚠ MISMATCH: Manual router $(ipv4_subnet "$manual_router").x vs gateway $(ipv4_subnet "$gw").x"
|
||||||
|
echo " → запустите: bash $SCRIPT_SELF recover"
|
||||||
|
elif [ -n "$current_ip" ] && [ "$current_ip" != "$manual_ip" ]; then
|
||||||
|
echo "⚠ MISMATCH: Manual IP $manual_ip, runtime $current_ip"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [ -n "$gw" ]; then
|
||||||
|
echo "--- gateway $gw ---"
|
||||||
|
arp -n "$gw" 2>/dev/null || true
|
||||||
|
route -n get "$gw" 2>/dev/null | grep -E 'interface|flags' || true
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
printf '%s\n' "Usage: $(basename "$0") status|recover" >&2
|
cat <<EOF
|
||||||
|
Usage: $(basename "$0") status|recover
|
||||||
|
|
||||||
|
recover — PAC/SOCKS off, DHCP, ядерный сброс (sudo), Joplin alias *.100
|
||||||
|
status — диагностика
|
||||||
|
|
||||||
|
Полная команда из любой папки:
|
||||||
|
bash $SCRIPT_SELF recover
|
||||||
|
EOF
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,69 +247,70 @@ cmd=$1
|
|||||||
|
|
||||||
case "$cmd" in
|
case "$cmd" in
|
||||||
status)
|
status)
|
||||||
echo "=== Wi-Fi device (hardware) ==="
|
echo "=== Wi-Fi device ==="
|
||||||
wifi_device || true
|
wifi_device || true
|
||||||
echo "=== networksetup -listallnetworkservices (excerpt) ==="
|
echo "=== IPv4 ==="
|
||||||
networksetup -listallnetworkservices 2>/dev/null | head -15 || true
|
print_manual_ipv4_status || true
|
||||||
echo "=== PAC / autoproxy (Wi-Fi + Thunderbolt Bridge 2 if present) ==="
|
echo "=== PAC ==="
|
||||||
if [ -x "$PAC_SCRIPT" ]; then
|
if [ -x "$PAC_SCRIPT" ]; then
|
||||||
MACOS_PAC_SERVICES="${MACOS_PAC_SERVICES:-Wi-Fi|Thunderbolt Bridge 2}" "$PAC_SCRIPT" status || true
|
MACOS_PAC_SERVICES="${MACOS_PAC_SERVICES:-Wi-Fi|Thunderbolt Bridge 2}" "$PAC_SCRIPT" status || true
|
||||||
fi
|
fi
|
||||||
echo "=== SOCKS firewall (Wi-Fi) ==="
|
echo "=== SOCKS (Wi-Fi) ==="
|
||||||
networksetup -getsocksfirewallproxy "Wi-Fi" 2>/dev/null || true
|
networksetup -getsocksfirewallproxy "Wi-Fi" 2>/dev/null || true
|
||||||
echo "=== Web proxy (Wi-Fi) ==="
|
echo "=== PAC listener :1089 ==="
|
||||||
networksetup -getwebproxy "Wi-Fi" 2>/dev/null || true
|
lsof -i :1089 -sTCP:LISTEN 2>/dev/null | head -3 || echo "(none)"
|
||||||
echo "=== Listener on 1089 (PAC URL default) ==="
|
|
||||||
if lsof -i :1089 -sTCP:LISTEN 2>/dev/null | head -5; then
|
|
||||||
:
|
|
||||||
else
|
|
||||||
echo "(none — при Enabled PAC в Safari/системе возможны сбои)"
|
|
||||||
fi
|
|
||||||
echo "=== Default route ==="
|
echo "=== Default route ==="
|
||||||
route -n get default 2>/dev/null | head -12 || true
|
route -n get default 2>/dev/null | head -8 || echo "(no default route)"
|
||||||
echo "=== Quick reachability (ICMP may be blocked on some hotspots) ==="
|
gw="$(default_gateway 2>/dev/null || true)"
|
||||||
ping -c 1 -W 2000 1.1.1.1 >/dev/null 2>&1 && echo "ping 1.1.1.1: ok" || echo "ping 1.1.1.1: fail"
|
if [ -n "$gw" ]; then
|
||||||
|
ping -c 1 -W 2000 "$gw" >/dev/null 2>&1 && echo "ping gateway: ok" || echo "ping gateway: fail"
|
||||||
|
fi
|
||||||
|
curl -sS --max-time 5 -o /dev/null https://1.1.1.1 2>/dev/null && echo "curl: ok" || echo "curl: fail"
|
||||||
;;
|
;;
|
||||||
recover)
|
recover)
|
||||||
echo "1) Отключаем автоматический PAC на выбранных сервисах..."
|
echo "=== Hotspot recover (DHCP + route flush) ==="
|
||||||
|
echo "Скрипт запросит пароль sudo для сброса маршрутов."
|
||||||
|
echo ""
|
||||||
|
echo "1) PAC off..."
|
||||||
if [ -x "$PAC_SCRIPT" ]; then
|
if [ -x "$PAC_SCRIPT" ]; then
|
||||||
MACOS_PAC_SERVICES="${MACOS_PAC_SERVICES:-Wi-Fi|Thunderbolt Bridge 2}" "$PAC_SCRIPT" off
|
MACOS_PAC_SERVICES="${MACOS_PAC_SERVICES:-Wi-Fi|Thunderbolt Bridge 2}" "$PAC_SCRIPT" off
|
||||||
else
|
|
||||||
echo "WARN: нет $PAC_SCRIPT — вручную: Системные настройки → Сеть → Wi‑Fi → Подробнее → Прокси → снять «Автоматическая настройка прокси»" >&2
|
|
||||||
fi
|
|
||||||
echo "2) Отключаем системный SOCKS-прокси на Wi-Fi (если был включён Shadowsocks и т.п.)..."
|
|
||||||
if networksetup -listallnetworkservices 2>/dev/null | grep -Fqx "Wi-Fi"; then
|
|
||||||
networksetup -setsocksfirewallproxystate "Wi-Fi" off 2>/dev/null || true
|
|
||||||
fi
|
|
||||||
echo "3) Сброс DNS-кэша (нужен sudo)..."
|
|
||||||
if sudo -n true 2>/dev/null; then
|
|
||||||
sudo dscacheutil -flushcache 2>/dev/null || true
|
|
||||||
sudo killall -HUP mDNSResponder 2>/dev/null || true
|
|
||||||
echo " mDNSResponder перезагружен."
|
|
||||||
else
|
|
||||||
echo " Пропуск (нет sudo без пароля). Выполните вручную:"
|
|
||||||
echo " sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder"
|
|
||||||
fi
|
fi
|
||||||
|
echo "2) SOCKS off..."
|
||||||
|
networksetup -setsocksfirewallproxystate "Wi-Fi" off 2>/dev/null || true
|
||||||
|
echo "3) Wi‑Fi → DHCP (снимаем конфликтный Manual Joplin)..."
|
||||||
|
ensure_dhcp_wifi
|
||||||
dev="$(wifi_device)"
|
dev="$(wifi_device)"
|
||||||
if [ -n "$dev" ]; then
|
if [ -z "$dev" ]; then
|
||||||
echo "4) Обновление DHCP на $dev (нужен sudo)..."
|
echo "Ошибка: Wi‑Fi device не найден" >&2
|
||||||
if sudo -n true 2>/dev/null; then
|
exit 1
|
||||||
sudo ipconfig set "$dev" DHCP 2>/dev/null || true
|
|
||||||
else
|
|
||||||
echo " Пропуск. Вручную: sudo ipconfig set $dev DHCP"
|
|
||||||
fi
|
|
||||||
echo "5) Краткое выключение/включение Wi‑Fi радиомодуля ($dev)..."
|
|
||||||
networksetup -setairportpower "$dev" off 2>/dev/null || true
|
|
||||||
sleep 2
|
|
||||||
networksetup -setairportpower "$dev" on 2>/dev/null || true
|
|
||||||
else
|
|
||||||
echo "4–5) Не удалось определить Wi‑Fi device — пропуск DHCP/airport power. Вручную выключите/включите Wi‑Fi в меню."
|
|
||||||
fi
|
fi
|
||||||
echo "=== Готово. Проверка: ==="
|
echo "4) Ядерный сброс $dev..."
|
||||||
"$0" status
|
nuclear_network_reset "$dev"
|
||||||
|
echo "5) Ожидание DHCP..."
|
||||||
|
wait_for_connectivity "$dev" || true
|
||||||
|
mode="$(joplin_mode)"
|
||||||
|
case "$mode" in
|
||||||
|
alias)
|
||||||
|
echo "6) Joplin: alias IP (не ломает маршрутизацию)..."
|
||||||
|
if [ -x "$JOPLIN_ALIAS_SCRIPT" ]; then
|
||||||
|
"$JOPLIN_ALIAS_SCRIPT" ensure || true
|
||||||
|
else
|
||||||
|
setup_joplin_alias "$dev" || true
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
manual)
|
||||||
|
echo "6) Joplin: manual Wi‑Fi (legacy)..."
|
||||||
|
setup_joplin_manual || true
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "6) Joplin: пропуск (нет $JOPLIN_ENV)"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
echo ""
|
echo ""
|
||||||
echo "Если интернет всё ещё нет: откройте хотспот в браузере (captive portal), затем при необходимости снова включите PAC:"
|
echo "=== Итог ==="
|
||||||
echo " ./docs/connectivity/scripts/macos-pac-on.sh"
|
"$SCRIPT_SELF" status
|
||||||
|
echo ""
|
||||||
|
echo "Captive portal: http://neverssl.com"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
usage
|
usage
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ find "$HOME/Library/Logs" -type f -size 0 -delete 2>/dev/null
|
|||||||
## 🔄 Регулярность очистки
|
## 🔄 Регулярность очистки
|
||||||
|
|
||||||
- **Еженедельно:** build-артефакты, пустые логи.
|
- **Еженедельно:** build-артефакты, пустые логи.
|
||||||
- **Ежемесячно:** кэши разработки (npm, node-gyp, TypeScript, pip, .yarn), Library/Caches (Google, Firefox, ShipIt, anytype-updater, ms-playwright, responsivelyapp-updater), Cursor WebStorage/Partitions/projects, уровень 1 из cleanup-disk-now.sh.
|
- **Ежемесячно:** кэши разработки (npm, node-gyp, TypeScript, pip, .yarn), Library/Caches (Google, Firefox, ShipIt, anytype-updater, ms-playwright), Cursor WebStorage/Partitions/projects.
|
||||||
- **При заполнении диска >80%:** всё из ежемесячного + Colima (если не нужен), state.vscdb.backup, приложения (Notion, zoom, LibreOffice, Movavi, Ledger), записи экрана.
|
- **При заполнении диска >80%:** всё из ежемесячного + Colima (если не нужен), state.vscdb.backup, приложения (Notion, zoom, LibreOffice, Movavi, Ledger), записи экрана.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -37,51 +37,14 @@ cleanup_dir "$HOME/.yarn" ".yarn кэш"
|
|||||||
cleanup_dir "$HOME/Library/Caches/ms-playwright" "Playwright кэш (браузеры для тестов)"
|
cleanup_dir "$HOME/Library/Caches/ms-playwright" "Playwright кэш (браузеры для тестов)"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# 2. Windsurf полностью (кэш + данные; приложение — удалить вручную из Программы)
|
# 2. Кэши браузеров — только Google/Firefox (Brave в DO_NOT_DELETE)
|
||||||
echo "=== 2. Windsurf полностью ==="
|
echo "=== 2. Кэши браузеров (не Brave) ==="
|
||||||
cleanup_dir "$HOME/.codeium/windsurf" "Codeium/Windsurf кэш"
|
|
||||||
cleanup_dir "$HOME/.windsurf" "Windsurf данные"
|
|
||||||
cleanup_dir "$HOME/Library/Application Support/Windsurf" "Windsurf Application Support"
|
|
||||||
# Если .codeium пуст — можно удалить целиком
|
|
||||||
[ -d "$HOME/.codeium" ] && [ -z "$(ls -A "$HOME/.codeium" 2>/dev/null)" ] && rm -rf "$HOME/.codeium" && echo " ✅ .codeium (пустая) удалена"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# 3. Кэши браузеров — только Google/Firefox (Brave в DO_NOT_DELETE)
|
|
||||||
echo "=== 3. Кэши браузеров (не Brave) ==="
|
|
||||||
cleanup_dir "$HOME/Library/Caches/Google" "Google кэш"
|
cleanup_dir "$HOME/Library/Caches/Google" "Google кэш"
|
||||||
cleanup_dir "$HOME/Library/Caches/Firefox" "Firefox кэш"
|
cleanup_dir "$HOME/Library/Caches/Firefox" "Firefox кэш"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# 3b. Уровень 1 — лёгкие кэши и временные артефакты (~0.5 GB)
|
# 3. Приложения — Notion, zoom, LibreOffice, Movavi, Ledger (Telegram в DO_NOT_DELETE)
|
||||||
echo "=== 3b. Уровень 1 (кэши приложений, Apple, hunabapp temp) ==="
|
echo "=== 3. Кэши приложений ==="
|
||||||
cleanup_dir "$HOME/Library/Caches/responsivelyapp-updater" "responsivelyapp-updater кэш"
|
|
||||||
cleanup_dir "$HOME/Library/Application Support/ResponsivelyApp" "ResponsivelyApp кэш"
|
|
||||||
cleanup_dir "$HOME/Library/Caches/GeoServices" "GeoServices кэш"
|
|
||||||
cleanup_dir "$HOME/Library/Caches/com.apple.helpd" "com.apple.helpd кэш"
|
|
||||||
cleanup_dir "$HOME/Library/Caches/com.apple.CloudTelemetry" "com.apple.CloudTelemetry кэш"
|
|
||||||
cleanup_dir "$HOME/Library/Caches/com.apple.ctcategories.service" "com.apple.ctcategories.service кэш"
|
|
||||||
HUNAB_TEMP="$HOME/code/hunabapp-dev/temp"
|
|
||||||
if [ -d "$HUNAB_TEMP" ]; then
|
|
||||||
find "$HUNAB_TEMP" -maxdepth 1 -type f \( -name 'hunab-backend-bundle-*.tar.gz' -o -name 'hunab-backend-logs-*.tar.gz' \) -print0 2>/dev/null | while IFS= read -r -d '' f; do
|
|
||||||
size=$(du -sh "$f" 2>/dev/null | cut -f1)
|
|
||||||
echo "🗑️ Удаление hunabapp temp: $(basename "$f") ($size)..."
|
|
||||||
rm -f "$f" && echo " ✅ удалён" || echo " ⚠️ не удалось"
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
echo " Build/dist в ~/code (кроме frontend/android)..."
|
|
||||||
find "$HOME/code" -type d \( -name "build" -o -name "dist" -o -name ".next" -o -name "out" \) \
|
|
||||||
-not -path "*/node_modules/*" \
|
|
||||||
-not -path "*/venv/*" \
|
|
||||||
-not -path "*/.venv/*" \
|
|
||||||
-not -path "*/site-packages/*" \
|
|
||||||
-not -path "*/env/*" \
|
|
||||||
-not -path "*/hunabapp-dev/frontend/android/*" \
|
|
||||||
-exec rm -rf {} + 2>/dev/null || true
|
|
||||||
echo " ✅ Build-артефакты уровня 1 очищены"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# 4. Приложения — Notion, zoom, LibreOffice, Movavi, Ledger (Telegram в DO_NOT_DELETE)
|
|
||||||
echo "=== 4. Кэши приложений ==="
|
|
||||||
cleanup_dir "$HOME/Library/Application Support/Notion" "Notion"
|
cleanup_dir "$HOME/Library/Application Support/Notion" "Notion"
|
||||||
cleanup_dir "$HOME/Library/Application Support/zoom.us" "zoom.us"
|
cleanup_dir "$HOME/Library/Application Support/zoom.us" "zoom.us"
|
||||||
cleanup_dir "$HOME/Library/Application Support/LibreOffice" "LibreOffice"
|
cleanup_dir "$HOME/Library/Application Support/LibreOffice" "LibreOffice"
|
||||||
@@ -89,8 +52,8 @@ cleanup_dir "$HOME/Library/Application Support/Movavi" "Movavi"
|
|||||||
cleanup_dir "$HOME/Library/Application Support/Ledger Live" "Ledger Live"
|
cleanup_dir "$HOME/Library/Application Support/Ledger Live" "Ledger Live"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# 5. Cursor — только разрешённые кэши и state backup (~10 GB)
|
# 4. Cursor — только разрешённые кэши и state backup (~10 GB)
|
||||||
echo "=== 5. Cursor кэши (только разрешённые) ==="
|
echo "=== 4. Cursor кэши (только разрешённые) ==="
|
||||||
STATE_BACKUP="$HOME/Library/Application Support/Cursor/User/globalStorage/state.vscdb.backup"
|
STATE_BACKUP="$HOME/Library/Application Support/Cursor/User/globalStorage/state.vscdb.backup"
|
||||||
if [ -f "$STATE_BACKUP" ]; then
|
if [ -f "$STATE_BACKUP" ]; then
|
||||||
size=$(du -sh "$STATE_BACKUP" 2>/dev/null | cut -f1)
|
size=$(du -sh "$STATE_BACKUP" 2>/dev/null | cut -f1)
|
||||||
@@ -109,35 +72,16 @@ cleanup_dir "$HOME/Library/Application Support/Cursor/Partitions" "Cursor Partit
|
|||||||
cleanup_dir "$HOME/.cursor/projects" "Cursor projects"
|
cleanup_dir "$HOME/.cursor/projects" "Cursor projects"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# 6. Homebrew, .cache, пустые логи
|
# 5. Homebrew, .cache, пустые логи
|
||||||
echo "=== 6. Homebrew, .cache, пустые логи ==="
|
echo "=== 5. Homebrew, .cache, пустые логи ==="
|
||||||
cleanup_dir "$HOME/Library/Caches/anytype-updater" "anytype-updater кэш"
|
cleanup_dir "$HOME/Library/Caches/anytype-updater" "anytype-updater кэш"
|
||||||
cleanup_dir "$HOME/Library/Caches/Homebrew" "Homebrew кэш"
|
cleanup_dir "$HOME/Library/Caches/Homebrew" "Homebrew кэш"
|
||||||
cleanup_dir "$HOME/.cache" ".cache"
|
cleanup_dir "$HOME/.cache" ".cache"
|
||||||
find "$HOME/Library/Logs" -type f -size 0 -delete 2>/dev/null && echo " ✅ Пустые логи удалены" || true
|
find "$HOME/Library/Logs" -type f -size 0 -delete 2>/dev/null && echo " ✅ Пустые логи удалены" || true
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# 7. ScreenRecordings (по желанию)
|
# 6. Build артефакты (исключая hunabapp-dev/frontend/android — в DO_NOT_DELETE)
|
||||||
echo "=== 7. Записи экрана ==="
|
echo "=== 6. Build артефакты в ~/code (кроме android) ==="
|
||||||
if [ -d "$HOME/Library/ScreenRecordings" ]; then
|
|
||||||
count=$(find "$HOME/Library/ScreenRecordings" -type f 2>/dev/null | wc -l | tr -d ' ')
|
|
||||||
if [ "$count" -gt 0 ]; then
|
|
||||||
echo " Найдено файлов: $count"
|
|
||||||
read -p " Удалить все записи экрана? (y/n): " -n 1 -r
|
|
||||||
echo
|
|
||||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
||||||
cleanup_dir "$HOME/Library/ScreenRecordings" "Записи экрана"
|
|
||||||
else
|
|
||||||
echo " ⏭️ Пропущено"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo " ℹ️ Папка пуста"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# 8. Build артефакты (исключая hunabapp-dev/frontend/android — в DO_NOT_DELETE)
|
|
||||||
echo "=== 8. Build артефакты в ~/code (кроме android) ==="
|
|
||||||
read -p " Удалить build/dist/.next/out? (y/n): " -n 1 -r
|
read -p " Удалить build/dist/.next/out? (y/n): " -n 1 -r
|
||||||
echo
|
echo
|
||||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||||
@@ -155,8 +99,8 @@ else
|
|||||||
fi
|
fi
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# 9. node_modules (опционально; НЕ frontend — в DO_NOT_DELETE)
|
# 7. node_modules (опционально; НЕ frontend — в DO_NOT_DELETE)
|
||||||
echo "=== 9. node_modules (кроме hunabapp-dev/frontend) ==="
|
echo "=== 7. node_modules (кроме hunabapp-dev/frontend) ==="
|
||||||
read -p " Удалить node_modules в проектах? (y/n): " -n 1 -r
|
read -p " Удалить node_modules в проектах? (y/n): " -n 1 -r
|
||||||
echo
|
echo
|
||||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||||
@@ -171,8 +115,8 @@ else
|
|||||||
fi
|
fi
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# 10. UTM виртуальная машина — опционально
|
# 8. UTM виртуальная машина — опционально
|
||||||
echo "=== 10. UTM виртуальная машина ==="
|
echo "=== 8. UTM виртуальная машина ==="
|
||||||
if [ -d "$HOME/code/Parrot-home-mate-6.4_arm64.utm" ]; then
|
if [ -d "$HOME/code/Parrot-home-mate-6.4_arm64.utm" ]; then
|
||||||
read -p " Удалить UTM виртуальную машину? (y/n): " -n 1 -r
|
read -p " Удалить UTM виртуальную машину? (y/n): " -n 1 -r
|
||||||
echo
|
echo
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
| **Исполняемый файл** | `C:\GOG Games\Jagged Alliance 3\JA3.exe` |
|
| **Исполняемый файл** | `C:\GOG Games\Jagged Alliance 3\JA3.exe` |
|
||||||
| **Bottle** | **GOG-Install** (`scripts/games/gog/bottle.env`) — не HoMM/Steam |
|
| **Bottle** | **GOG-Install** (`scripts/games/gog/bottle.env`) — не HoMM/Steam |
|
||||||
| **Galaxy в Wine** | **не использовать** для JA3 — CEF, swap ([GOG_GALAXY_7H_RCA.md](GOG_GALAXY_7H_RCA.md)) |
|
| **Galaxy в Wine** | **не использовать** для JA3 — CEF, swap ([GOG_GALAXY_7H_RCA.md](GOG_GALAXY_7H_RCA.md)) |
|
||||||
| **Запуск игры** | **CrossOver** `run-ja3-crossover.sh` — см. [JA3_RUNBOOK.md](JA3_RUNBOOK.md) |
|
| **Запуск игры** | **`run-ja3.sh`** (Whisky GOG-Install) — см. [JA3_RUNBOOK.md](JA3_RUNBOOK.md) |
|
||||||
| **Steam.app / Steam.exe** | **не в контуре** — отдельный bottle HoMM; в GOG-bottle клиента Steam быть не должно |
|
| **Steam.app / Steam.exe** | **не в контуре** — отдельный bottle HoMM; в GOG-bottle клиента Steam быть не должно |
|
||||||
|
|
||||||
### Не путать с Steam
|
### Не путать с Steam
|
||||||
@@ -126,33 +126,26 @@ JA3 на Windows использует **D3D12**. **DXVK-macOS** (только D3
|
|||||||
| **Whisky / Gcenx Wine 11.9** | `d3d12.dll` = wined3d → **Vulkan** (`d3d12_get_vk_physical_device Could not find Vulkan physical device`). **Нет D3DMetal hooks** ([Gcenx#97](https://github.com/Gcenx/macOS_Wine_builds/issues/97)). |
|
| **Whisky / Gcenx Wine 11.9** | `d3d12.dll` = wined3d → **Vulkan** (`d3d12_get_vk_physical_device Could not find Vulkan physical device`). **Нет D3DMetal hooks** ([Gcenx#97](https://github.com/Gcenx/macOS_Wine_builds/issues/97)). |
|
||||||
| **GPTK PE + Gcenx ntdll** | `__wine_unix_call` / `dxgi.dll not found` — PE DLL GPTK несовместимы с чужим Wine. |
|
| **GPTK PE + Gcenx ntdll** | `__wine_unix_call` / `dxgi.dll not found` — PE DLL GPTK несовместимы с чужим Wine. |
|
||||||
| **GPTK Wine 7.7 alone** | `comctl32.dll failed to initialize` на этой macOS — не запускается даже notepad. |
|
| **GPTK Wine 7.7 alone** | `comctl32.dll failed to initialize` на этой macOS — не запускается даже notepad. |
|
||||||
| **CrossOver 26 + D3DMetal** | **Работает.** Встроенные `apple_gptk` + `WINED3DMETAL=1`. |
|
| **CrossOver 26 + D3DMetal** | Работало; **CrossOver удалён** (2026-06). |
|
||||||
|
| **Whisky + GPTK** | D3DMetal в GOG-Install bottle — см. `install-gptk-whisky.sh` |
|
||||||
|
|
||||||
Сообщения GOG API (`MatchmakingServers`, `Music`, `Game name not defined`) — **не причина** краша.
|
Сообщения GOG API (`MatchmakingServers`, `Music`, `Game name not defined`) — **не причина** краша.
|
||||||
|
|
||||||
#### Канон запуска (подтверждено на этой машине)
|
#### Канон запуска (2026-06)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
brew install --cask crossover # один раз
|
bash ~/code/local_machine/scripts/games/gog/run-ja3.sh
|
||||||
bash ~/code/local_machine/scripts/games/gog/setup-ja3-crossover.sh
|
|
||||||
bash ~/code/local_machine/scripts/games/gog/run-ja3-crossover.sh
|
|
||||||
```
|
```
|
||||||
|
|
||||||
CrossOver bottle **JA3-GOG** (win10_64, D3DMetal on). Игра клонируется APFS clonefile в bottle (Wine **не читает** symlink за пределы prefix → `CommonLua/Core/autorun.lua not found`).
|
Игра в bottle **GOG-Install** (Whisky). При D3D12-ошибках — GPTK в bottle ([JA3_RUNBOOK.md](JA3_RUNBOOK.md) §2).
|
||||||
|
|
||||||
**Whisky `run-ja3.sh` для D3D12 на Mac не работает** — только CrossOver (или Porting Kit GUI).
|
|
||||||
|
|
||||||
Альтернатива GUI: [Porting Kit](https://www.paulthetall.com/jagged-aliance-3-for-mac/) (тот же GPTK/D3DMetal стек).
|
|
||||||
|
|
||||||
### Запуск игры
|
### Запуск игры
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bash ~/code/local_machine/scripts/games/gog/run-ja3-crossover.sh
|
bash ~/code/local_machine/scripts/games/gog/run-ja3.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
Whisky (`run-ja3.sh`) — только установка innoextract в GOG-Install; **графика D3D12 → CrossOver**.
|
Обход swap (тормоза, на свой риск):
|
||||||
|
|
||||||
Обход (тормоза, на свой риск):
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
JA3_IGNORE_SWAP=1 bash ~/code/local_machine/scripts/games/gog/run-ja3.sh
|
JA3_IGNORE_SWAP=1 bash ~/code/local_machine/scripts/games/gog/run-ja3.sh
|
||||||
@@ -160,7 +153,7 @@ JA3_IGNORE_SWAP=1 bash ~/code/local_machine/scripts/games/gog/run-ja3.sh
|
|||||||
|
|
||||||
Cmd+Tab → `wine64` / `JA3`. В графике при артефактах: **отключить heat haze**.
|
Cmd+Tab → `wine64` / `JA3`. В графике при артефактах: **отключить heat haze**.
|
||||||
|
|
||||||
**Ошибка «Failed to initialize graphics subsystem»:** Whisky/Gcenx Wine **не поддерживает D3DMetal** для d3d12. Используйте **CrossOver**: `setup-ja3-crossover.sh` + `run-ja3-crossover.sh`. Из Whisky Run **не запускать** — только CrossOver bottle JA3-GOG с `start /d` (CWD + CommonLua).
|
**Ошибка «Failed to initialize graphics subsystem»:** установите GPTK и настройте D3DMetal в Whisky — см. [JA3_RUNBOOK.md](JA3_RUNBOOK.md) §2. **Не** запускать `JA3.exe` из Whisky Run без `start /d`.
|
||||||
|
|
||||||
### Итог на диске (после успеха на этой машине)
|
### Итог на диске (после успеха на этой машине)
|
||||||
|
|
||||||
@@ -200,9 +193,8 @@ bash ~/code/local_machine/scripts/games/gog/install-ja3-offline.sh ~/Downloads/s
|
|||||||
| `install-ja3-multipart.sh` (Wine `/VERYSILENT`) | `install-ja3-innoextract.sh` |
|
| `install-ja3-multipart.sh` (Wine `/VERYSILENT`) | `install-ja3-innoextract.sh` |
|
||||||
| Распаковка в `scripts/games/cache/ja3-*` | сразу в `drive_c/GOG Games/…` |
|
| Распаковка в `scripts/games/cache/ja3-*` | сразу в `drive_c/GOG Games/…` |
|
||||||
| Держать `.bin` после установки без нужды | скрипт удалит (~15 GB) |
|
| Держать `.bin` после установки без нужды | скрипт удалит (~15 GB) |
|
||||||
| `launch-galaxy.sh` / Galaxy CEF для JA3 | **`run-ja3-crossover.sh`** ([JA3_RUNBOOK.md](JA3_RUNBOOK.md)) |
|
| `launch-galaxy.sh` / Galaxy CEF для JA3 | **`run-ja3.sh`** ([JA3_RUNBOOK.md](JA3_RUNBOOK.md)) |
|
||||||
| Whisky `run-ja3.sh` для D3D12 | CrossOver + D3DMetal |
|
| Whisky Run `JA3.exe` без CWD | `run-ja3.sh` (`start /d`) |
|
||||||
| `RetinaMode=y` + `LogPixels=192` для мыши JA3 | Клип курсора на середине экрана → **legacy** ([JA3_RUNBOOK.md](JA3_RUNBOOK.md) §9) |
|
|
||||||
| Жёсткий стоп JA3 при swap 800 MB без Wine | Устарело; warn до 4 GB — [JA3_RUNBOOK.md](JA3_RUNBOOK.md) §4 |
|
| Жёсткий стоп JA3 при swap 800 MB без Wine | Устарело; warn до 4 GB — [JA3_RUNBOOK.md](JA3_RUNBOOK.md) §4 |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
# Jagged Alliance 3 (GOG) — runbook Mac / Apple Silicon
|
# Jagged Alliance 3 (GOG) — runbook Mac / Apple Silicon
|
||||||
|
|
||||||
**Машина:** M1 Pro, macOS Sonoma+, bottle Whisky **GOG-Install** (`9ee55e7c-a58e-411e-a93f-30530d4f1073`).
|
**Машина:** M1 Pro, macOS Sonoma+, bottle Whisky **GOG-Install** (`9ee55e7c-a58e-411e-a93f-30530d4f1073`).
|
||||||
**Проверено:** 2026-05-28 (установка) · 2026-05-29 (запуск через CrossOver).
|
**Проверено:** 2026-05-28 (установка) · 2026-06-17 (CrossOver удалён; запуск только Whisky).
|
||||||
|
|
||||||
Связанные документы: [JA3_MAC_WITHOUT_GALAXY.md](JA3_MAC_WITHOUT_GALAXY.md) (установка offline), [TROUBLESHOOTING.md](TROUBLESHOOTING.md), [GOG_GALAXY_7H_RCA.md](GOG_GALAXY_7H_RCA.md).
|
Связанные документы: [JA3_MAC_WITHOUT_GALAXY.md](JA3_MAC_WITHOUT_GALAXY.md), [TROUBLESHOOTING.md](TROUBLESHOOTING.md), [GOG_GALAXY_7H_RCA.md](GOG_GALAXY_7H_RCA.md).
|
||||||
|
|
||||||
|
> **Примечание (2026-06):** CrossOver и связанные скрипты (`run-ja3-crossover.sh`, `JA3-GOG`, `JA3-WINE`, `sync-ja3-saves.sh`) **удалены** с машины. Запуск JA3 — только через Whisky GOG-Install.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -17,281 +19,93 @@ bash ~/code/local_machine/scripts/games/gog/install-ja3-innoextract.sh
|
|||||||
bash ~/code/local_machine/scripts/games/gog/finish-ja3-layout.sh
|
bash ~/code/local_machine/scripts/games/gog/finish-ja3-layout.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
### Запуск (каждый раз, CrossOver + D3DMetal)
|
### Запуск (каждый раз)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
brew install --cask crossover # один раз
|
bash ~/code/local_machine/scripts/games/gog/run-ja3.sh
|
||||||
bash ~/code/local_machine/scripts/games/gog/setup-ja3-crossover.sh # один раз
|
|
||||||
bash ~/code/local_machine/scripts/games/gog/run-ja3-crossover.sh
|
|
||||||
```
|
```
|
||||||
|
|
||||||
- **Cmd+Tab** → окно `JA3.exe`
|
- **Cmd+Tab** → окно **`JA3.exe`**
|
||||||
- В настройках графики: **отключить heat haze**
|
- **Swap:** «залипший» swap после Wine **не блокирует** запуск — только предупреждение. Стоп: swap ≥ **4096 MB** без Wine, или swap ≥ **1200 MB** пока **Wine/JA3 ещё работают** → `reset-ja3-whisky.sh` / reboot. Обход: `JA3_IGNORE_SWAP=1`
|
||||||
- **Swap:** «залипший» swap после Wine (2–4 GB без процессов) **не блокирует** запуск — только предупреждение. Стоп: swap ≥ **4096 MB** без Wine, или swap ≥ **1200 MB** пока **Wine/JA3 ещё работают** → `reset-ja3-crossover.sh` / reboot. Обход: `JA3_IGNORE_SWAP=1`
|
- **Задержка cold start:** 15–60 с до появления окна — норма
|
||||||
|
|
||||||
### Два «контура»
|
|
||||||
|
|
||||||
| Контур | Роль | Инструмент |
|
|
||||||
|--------|------|------------|
|
|
||||||
| **GOG-Install** (Whisky) | innoextract, файлы игры, CommonLua, реестр GOG | `install-ja3-innoextract.sh`, `finish-ja3-layout.sh` |
|
|
||||||
| **JA3-GOG** (CrossOver) | **запуск** D3D12 через D3DMetal | `setup-ja3-crossover.sh`, `run-ja3-crossover.sh` |
|
|
||||||
|
|
||||||
Whisky **`run-ja3.sh` не запускает JA3 с рабочей графикой** — только CrossOver (или Porting Kit GUI).
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2. Почему CrossOver, а не Whisky
|
## 2. Графика: Whisky vs D3D12
|
||||||
|
|
||||||
JA3 на Windows использует **DirectX 12**. На Apple Silicon единственный рабочий путь — **Apple D3DMetal** (Game Porting Toolkit), встроенный в **CrossOver 23+** с флагом `WINED3DMETAL=1`.
|
JA3 на Windows использует **DirectX 12**. На Apple Silicon рабочий путь раньше был **CrossOver + D3DMetal** — CrossOver снят.
|
||||||
|
|
||||||
**Whisky** использует **Gcenx Wine** — maintainer явно пишет, что сборки **не содержат D3DMetal hooks** ([Gcenx/macOS_Wine_builds#97](https://github.com/Gcenx/macOS_Wine_builds/issues/97)). В этом случае `d3d12.dll` (94 KB) идёт через **wined3d → Vulkan**, а на Mac нет Vulkan physical device:
|
**Сейчас:** `run-ja3.sh` запускает игру в **Whisky GOG-Install**:
|
||||||
|
- с **GPTK/D3DMetal** в bottle (если установлен Game Porting Toolkit) — D3D12;
|
||||||
```text
|
- иначе **DXVK D3D11 fallback** (`-graphicsapi d3d11`).
|
||||||
fixme:d3d12:d3d12_get_vk_physical_device Could not find Vulkan physical device for DXGI adapter.
|
|
||||||
```
|
|
||||||
|
|
||||||
→ UI: **«Failed to initialize graphics subsystem»**
|
|
||||||
→ лог JA3: **`Failed creating render device`**
|
|
||||||
|
|
||||||
Копирование `D3DMetal.framework` + `libd3dshared.dylib` + моста `d3d12.so` **не достаточно**, если PE `d3d12.dll` / `ntdll` от Gcenx — unix-вызовы D3DMetal не подключены.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3. RCA: злоключения 2026-05-28 — 2026-05-29
|
|
||||||
|
|
||||||
Хронология попыток на этой машине (чат + логи `JA3.exe-*.log`, Wine debug).
|
|
||||||
|
|
||||||
### Фаза A — установка и ложные следы (28.05)
|
|
||||||
|
|
||||||
| # | Симптом / действие | Реальная причина | Итог |
|
|
||||||
|---|-------------------|------------------|------|
|
|
||||||
| A1 | GOG web-stub, пустые кнопки | Нет **gdiplus** (winetricks) | ✅ `install-gdiplus.sh` + corefonts |
|
|
||||||
| A2 | Galaxy CEF, окна нет | HWND/CEF в Wine, swap | Galaxy **не нужен** для JA3 offline |
|
|
||||||
| A3 | Лог `Steam initialized … Beta branch GOG` | GOG API-шим (`steam_api64.dll`), **не** Steam.app | ❌ не причина краша |
|
|
||||||
| A4 | `CreateSubsystem failed MatchmakingServers/Music` | GOG wrapper без Galaxy service | ❌ шум, не графика |
|
|
||||||
| A5 | `Game name not defined` | innoextract не выполнил Inno-постскрипты | ⚠️ косметика; фикс: `register-ja3-registry.sh` |
|
|
||||||
| A6 | Swap ~3 GB, скрипт блокирует запуск | «Залипший» swap после Wine; macOS не отдаёт без reboot | ✅ `gog_swap_guard_ja3_launch`: warn до 4 GB без процессов; reboot если Mac тормозит |
|
|
||||||
|
|
||||||
### Фаза B — «графика» в Whisky (28–29.05)
|
|
||||||
|
|
||||||
| # | Попытка | Лог / ошибка | Почему не работает |
|
|
||||||
|---|---------|--------------|-------------------|
|
|
||||||
| B1 | DXVK + `-graphicsapi d3d11` | `Failed creating render device` | DXVK = D3D10/11, **не D3D12** |
|
|
||||||
| B2 | DXMT v0.80 | `dxgi.dll` **c000007b** | Несовместимость с Gcenx Wine 11 + overrides |
|
|
||||||
| B3 | `upgrade-whisky-wine-gcenx.sh` (11.9) + GPTK bridge | `d3d12_get_vk_physical_device` | Gcenx d3d12 = **Vulkan**, не Metal |
|
|
||||||
| B4 | GPTK PE `d3d12.dll`/`dxgi.dll` (114/86 KB) в `system32` | Всё ещё Vulkan path или `dxgi not found` | PE GPTK 7.7 ≠ ntdll Gcenx 11 |
|
|
||||||
| B5 | GPTK PE в `wine/lib/x86_64-windows` | `Library dxgi.dll not found` (c0000135) | `__wine_unix_call` не реализован в Gcenx ntdll |
|
|
||||||
| B6 | Замена `ntdll.so` на GPTK | `virtual_alloc_first_teb` / wine не стартует | Нельзя мешать ntdll разных Wine |
|
|
||||||
| B7 | `ditto` всего GPTK `lib/` в Whisky | Wine **7.7 GPTK** поверх bottle | Перезаписал `wine64` → comctl32 и др. |
|
|
||||||
| B8 | `prepare-ja3-d3dmetal.sh` (убрать d3d12 из system32) | Всё равно render device fail | Builtin Gcenx d3d12 без Metal |
|
|
||||||
| B9 | `forceD3D11: true` в Metadata.plist | Противоречие с D3D12 backend | Исправлено на `false` — без эффекта на Gcenx |
|
|
||||||
| B10 | GPTK Wine 7.7, отдельный prefix | `comctl32.dll failed to initialize` (c0000005) | GPTK Wine 7.7 **сломан** на этой macOS |
|
|
||||||
| B11 | `fixmywhisky.sh` (ditto GPTK lib) | Как B7 | Только D3DMetal.framework + bridge **без** подмены всего Wine |
|
|
||||||
|
|
||||||
### Фаза C — CrossOver (29.05, **успех**)
|
|
||||||
|
|
||||||
| # | Шаг | Результат |
|
|
||||||
|---|-----|-----------|
|
|
||||||
| C1 | `brew install --cask crossover` | CrossOver 26.1, встроенный `apple_gptk` |
|
|
||||||
| C2 | Bottle **JA3-GOG**, template **win10_64** (не win32 Wow64!) | `kernel32` c000007b на 32-bit bottle |
|
|
||||||
| C3 | `WINED3DMETAL=1`, `WINEDXVK=0` в `cxbottle.conf` | D3D12 → Metal |
|
|
||||||
| C4 | Symlink игры из Whisky bottle | `CommonLua/Core/autorun.lua: File Not Found` — Wine **не читает** symlink **вне** prefix |
|
|
||||||
| C5 | `cp -cR` (APFS clonefile) игры в CrossOver bottle | Файлы видны Wine; **~0** доп. места на APFS |
|
|
||||||
| C6 | `start /d "C:\GOG Games\Jagged Alliance 3" JA3.exe -unpacked` | CWD с `CommonLua/`; не `--cx-app` без `/d` |
|
|
||||||
| C7 | Запуск | **JA3.exe** стабильно работает, нет `Failed creating render device` |
|
|
||||||
| C8 | Курсор: смещение клика → `RetinaMode=y` + `LogPixels=192` | Курсор **не опускается ниже середины экрана** (Y делится пополам) | ✅ профиль **`legacy`**: `RetinaMode=n`, без LogPixels — **подтверждено 2026-05-29** |
|
|
||||||
|
|
||||||
### Сигнатуры в логах (диагностика)
|
|
||||||
|
|
||||||
| Строка | Значение |
|
|
||||||
|--------|----------|
|
|
||||||
| `Failed creating render device` | D3D12 не дошёл до GPU — Whisky/Gcenx, не CrossOver |
|
|
||||||
| `d3d12_get_vk_physical_device Could not find Vulkan` | Gcenx wined3d path — нужен CrossOver D3DMetal |
|
|
||||||
| `Failed to initialize graphics subsystem` (UI) | То же, пользовательский текст JA3 |
|
|
||||||
| `Error opening 'CommonLua/Core/autorun.lua'` | Нет CWD (`start /d`) или symlink вместо клона в bottle |
|
|
||||||
| `comctl32.dll failed to initialize` | GPTK Wine 7.7 — не использовать |
|
|
||||||
| `__wine_unix_call` / `aborting` | GPTK PE на чужом Wine |
|
|
||||||
| `dxgi.dll` **c000007b** | DXMT + неправильные overrides |
|
|
||||||
| `Language: English` без `Failed creating` | Графика OK; смотреть CommonLua / crash дальше |
|
|
||||||
| Курсор виден, клик смещён по Y | HiDPI без согласованного масштаба Wine | `fix-ja3-crossover-mouse.sh` → профиль **legacy** |
|
|
||||||
| Курсор **не ниже середины экрана** | `RetinaMode=y` + `LogPixels=192` / двойной DPI | **legacy** (не retina); перезапуск JA3 |
|
|
||||||
|
|
||||||
Логи JA3:
|
|
||||||
`…/AppData/Roaming/Jagged Alliance 3/logs/JA3.exe-*.log`
|
|
||||||
Whisky: `…/Containers/com.franke.Whisky/Bottles/9ee55e7c-…/`
|
|
||||||
CrossOver: `~/Library/Application Support/CrossOver/Bottles/JA3-GOG/`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 4. Антипаттерны (полный список)
|
|
||||||
|
|
||||||
### Установка
|
|
||||||
|
|
||||||
| ❌ Не делать | ✅ Вместо |
|
|
||||||
|-------------|----------|
|
|
||||||
| GOG web-stub `GOG_Galaxy_Jagged_Alliance_3.exe` | Offline backup 5 частей в `~/Games/` |
|
|
||||||
| `install-ja3-multipart.sh` (Wine Inno) | `install-ja3-innoextract.sh` |
|
|
||||||
| Распаковка в `scripts/games/cache/` | Сразу в `drive_c/GOG Games/…` |
|
|
||||||
| Bottle **HoMM-OldenEra** (Steam) | Bottle **GOG-Install** |
|
|
||||||
| Удалять `steam_api64.dll` в папке игры | Это GOG-шим, **оставить** |
|
|
||||||
| Steam client в GOG-bottle | `purge-steam-from-bottle.sh` |
|
|
||||||
|
|
||||||
### Графика / Wine
|
|
||||||
|
|
||||||
| ❌ Не делать | ✅ Вместо |
|
|
||||||
|-------------|----------|
|
|
||||||
| Whisky `run-ja3.sh` для игры | **`run-ja3-crossover.sh`** |
|
|
||||||
| `upgrade-whisky-wine-gcenx.sh` «для D3DMetal» | Gcenx **не** поддерживает D3DMetal hooks |
|
|
||||||
| `ditto` всего GPTK `lib/` в Whisky Libraries | Только `D3DMetal.framework` + `libd3dshared` + `.so` bridge (см. `install-gptk-whisky.sh`) |
|
|
||||||
| GPTK PE `d3d12/dxgi` в system32 **Whisky** | CrossOver со встроенным `apple_gptk` |
|
|
||||||
| Замена `ntdll.so` GPTK в Gcenx Wine | Ломает preloader |
|
|
||||||
| DXVK / DXMT для JA3 как «замена D3D12» | Не подтверждено; JA3 = D3D12 |
|
|
||||||
| `dxgi,d3d11=n,b` с DXMT | Ломает цепочку → c000007b |
|
|
||||||
| Whisky Run **`JA3.exe`** без CWD | `start /d` или `run-ja3.cmd` (Whisky) / CrossOver `start /d` |
|
|
||||||
| Symlink игры из Whisky в CrossOver bottle | **`cp -cR`** (APFS clone) |
|
|
||||||
| CrossOver bottle **win32** / Wow64 | **`win10_64`** |
|
|
||||||
| `--cx-app JA3.exe` без `start /d` | `start /d "…Jagged Alliance 3" JA3.exe -unpacked` |
|
|
||||||
| `forceD3D11: true` + backend d3dMetal | `forceD3D11: false` (Metadata Whisky — не решает Gcenx) |
|
|
||||||
|
|
||||||
### Окружение
|
|
||||||
|
|
||||||
| ❌ Не делать | ✅ Вместо |
|
|
||||||
|-------------|----------|
|
|
||||||
| Считать «залипший» swap 2–4 GB блокером JA3 | Запуск разрешён (warn); reboot — если Mac тормозит |
|
|
||||||
| Запуск JA3 при swap ≥ **1200 MB** + **Wine/JA3 ещё работают** | `reset-ja3-crossover.sh` → reboot |
|
|
||||||
| Запуск JA3 при swap ≥ **4096 MB** без Wine | Reboot Mac или `JA3_IGNORE_SWAP=1` |
|
|
||||||
| Жёсткий лимит **800 MB** для `run-ja3-crossover.sh` | Устарело; см. `gog_swap_guard_ja3_launch` в `config.sh` |
|
|
||||||
| Путать лог Galaxy с JA3 | JA3 offline **без** Galaxy UI |
|
|
||||||
| Чинить «graphics» через Galaxy service | `MatchmakingServers`/`Music` — шум GOG API |
|
|
||||||
|
|
||||||
### Мышь (CrossOver / Retina)
|
|
||||||
|
|
||||||
| ❌ Не делать | ✅ Вместо |
|
|
||||||
|-------------|----------|
|
|
||||||
| `RetinaMode=y` + `LogPixels=192` + `Win8DpiScaling=1` «по умолчанию» | **`fix-ja3-crossover-mouse.sh`** — профиль **legacy** (`RetinaMode=n`) |
|
|
||||||
| CrossOver GUI **High Resolution Mode** без проверки | Если клип Y на середине → **legacy** |
|
|
||||||
| Менять реестр мыши без перезапуска JA3 | `reset-ja3-crossover.sh` → `run-ja3-crossover.sh` |
|
|
||||||
| Профиль **retina** при клипе на середине экрана | **legacy**; при смещении клика — **retina-lite** |
|
|
||||||
| Ожидать фикс мыши «на лету» | Workaround: верхний левый угол окна = угол экрана |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 5. Скрипты
|
|
||||||
|
|
||||||
| Скрипт | Назначение | Статус |
|
|
||||||
|--------|------------|--------|
|
|
||||||
| `install-ja3-innoextract.sh` | Multipart offline → bottle | ✅ канон установки |
|
|
||||||
| `finish-ja3-layout.sh` | CommonLua, реестр, upscale DLL | ✅ после innoextract |
|
|
||||||
| `setup-ja3-crossover.sh` | Bottle JA3-GOG, clone игры, D3DMetal | ✅ один раз |
|
|
||||||
| **`run-ja3-crossover.sh`** | **Запуск игры** | ✅ **канон** |
|
|
||||||
| `reset-ja3-crossover.sh` | Stop JA3 / Wine перед перезапуском | ✅ |
|
|
||||||
| `fix-ja3-crossover-mouse.sh` | Профили мыши (legacy / retina-lite / retina) | ✅ default **legacy** |
|
|
||||||
| `run-ja3.sh` | Whisky (эксперимент; графика fail) | ⚠️ только с предупреждением |
|
|
||||||
| `prepare-ja3-d3dmetal.sh` | Whisky D3DMetal prep | ⚠️ не решает Gcenx d3d12 |
|
|
||||||
| `upgrade-whisky-wine-gcenx.sh` | Wine 11.9 | ❌ для JA3 не использовать |
|
|
||||||
| `run-ja3-gptk-wine.sh` | GPTK Wine 7.7 prefix | ❌ comctl32 на этой Mac |
|
|
||||||
| `install-ja3-dxmt.sh` | DXMT fallback d3d11 | ❌ c000007b |
|
|
||||||
| `emergency-stop.sh` | Kill Wine/GOG перед запуском | ✅ |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 6. CrossOver bottle (детали)
|
|
||||||
|
|
||||||
**Путь:** `~/Library/Application Support/CrossOver/Bottles/JA3-GOG/`
|
|
||||||
|
|
||||||
**cxbottle.conf** (минимум):
|
|
||||||
|
|
||||||
```ini
|
|
||||||
"WINED3DMETAL" = "1"
|
|
||||||
"WINEDXVK" = "0"
|
|
||||||
```
|
|
||||||
|
|
||||||
**Игра:** `drive_c/GOG Games/Jagged Alliance 3/` — APFS-клон из Whisky GOG-Install (не symlink).
|
|
||||||
|
|
||||||
**Проверка:**
|
|
||||||
|
|
||||||
|
При ошибке `Failed to initialize graphics subsystem` / `dxgi.dll not found`:
|
||||||
```bash
|
```bash
|
||||||
pgrep -fl 'JA3\.exe'
|
brew install --cask gcenx/wine/game-porting-toolkit
|
||||||
grep -E 'Failed creating|autorun|CRASH' \
|
bash ~/code/local_machine/scripts/games/gog/install-gptk-whisky.sh
|
||||||
"$HOME/Library/Application Support/CrossOver/Bottles/JA3-GOG/drive_c/users/"*/AppData/Roaming/Jagged\ Alliance\ 3/logs/*.log | tail
|
bash ~/code/local_machine/scripts/games/gog/configure-ja3-d3dmetal.sh
|
||||||
|
bash ~/code/local_machine/scripts/games/gog/run-ja3.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7. Альтернативы
|
## 3. Пути на диске
|
||||||
|
|
||||||
| Вариант | Комментарий |
|
| Что | Путь |
|
||||||
|---------|-------------|
|
|-----|------|
|
||||||
| [Porting Kit](https://www.paulthetall.com/jagged-aliance-3-for-mac/) + GOG offline | Тот же GPTK/D3DMetal; GUI, «просто работает» на M-series |
|
| Игра (Whisky) | `…/Containers/com.franke.Whisky/Bottles/9ee55e7c-…/drive_c/GOG Games/Jagged Alliance 3/` |
|
||||||
| CrossOver GUI | Bottle JA3-GOG → Install → Run exe; D3DMetal в Advanced Settings |
|
| Сейвы | `…/drive_c/users/eternal/AppData/Roaming/Jagged Alliance 3/<account_id>/` |
|
||||||
| Whisky + GPTK drag DMG | [Whisky#124](https://github.com/Whisky-App/Whisky/issues/124) — для **DX12** на Gcenx всё равно нет hooks |
|
| Логи JA3 | `…/AppData/Roaming/Jagged Alliance 3/logs/JA3.exe-*.log` |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 9. Курсор: HiDPI / Retina (CrossOver)
|
## 4. Скрипты
|
||||||
|
|
||||||
**Проверено 2026-05-29** на M1 Pro + CrossOver 26.1, bottle **JA3-GOG**.
|
| Скрипт | Назначение |
|
||||||
|
|--------|------------|
|
||||||
|
| `install-ja3-innoextract.sh` | Установка из offline backup |
|
||||||
|
| `finish-ja3-layout.sh` | CommonLua, реестр GOG |
|
||||||
|
| **`run-ja3.sh`** | **Канон запуска** |
|
||||||
|
| `reset-ja3-whisky.sh` | Остановить JA3/Wine в GOG-Install |
|
||||||
|
| `emergency-stop.sh` | Полный стоп GOG/Wine |
|
||||||
|
| `prepare-ja3-d3dmetal.sh` / `configure-ja3-d3dmetal.sh` | D3DMetal в Whisky |
|
||||||
|
|
||||||
### Симптомы
|
**Удалено (CrossOver):** `run-ja3-crossover.sh`, `setup-ja3-crossover.sh`, `run-ja3-wine.sh`, `sync-ja3-saves.sh`, `fix-ja3-crossover-mouse.sh`.
|
||||||
|
|
||||||
| Симптом | Типичная причина |
|
|
||||||
|---------|------------------|
|
|
||||||
| Клик «выше/ниже» UI, курсор виден | Wine отдаёт logical pixels, игра рисует в другом масштабе |
|
|
||||||
| **Курсор не опускается ниже середины экрана** | `RetinaMode=y` + `LogPixels=192` — координата Y делится пополам |
|
|
||||||
|
|
||||||
### Профили (`fix-ja3-crossover-mouse.sh`)
|
|
||||||
|
|
||||||
| Профиль | Реестр | Когда |
|
|
||||||
|---------|--------|-------|
|
|
||||||
| **`legacy`** (default) | `RetinaMode=n`, LogPixels/Win8Dpi **удалены** | **Канон** — полный ход курсора по Y; возможен небольшой сдвиг клика |
|
|
||||||
| `retina-lite` | `RetinaMode=y`, без LogPixels | Если legacy смещает клик, но **нет** клипа на середине |
|
|
||||||
| `retina` | `RetinaMode=y`, `LogPixels=192`, `Win8DpiScaling=1` | ❌ часто **клип Y на 50%** — не использовать как default |
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Канон (после смены профиля — перезапуск JA3)
|
|
||||||
bash ~/code/local_machine/scripts/games/gog/fix-ja3-crossover-mouse.sh
|
|
||||||
bash ~/code/local_machine/scripts/games/gog/reset-ja3-crossover.sh
|
|
||||||
bash ~/code/local_machine/scripts/games/gog/run-ja3-crossover.sh
|
|
||||||
|
|
||||||
# Если legacy смещает клик
|
|
||||||
JA3_MOUSE_PROFILE=retina-lite bash ~/code/local_machine/scripts/games/gog/fix-ja3-crossover-mouse.sh
|
|
||||||
bash ~/code/local_machine/scripts/games/gog/reset-ja3-crossover.sh
|
|
||||||
bash ~/code/local_machine/scripts/games/gog/run-ja3-crossover.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
**Без перезапуска (workaround):** перетащите окно JA3 так, чтобы **верхний левый угол окна** совпал с **верхним левым углом экрана**.
|
|
||||||
|
|
||||||
CrossOver GUI: Bottle **JA3-GOG** → **High Resolution Mode** — при клипе на середине **выключить** (эквивалент **legacy**).
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 10. Быстрые команды (терминал)
|
## 5. Антипаттерны
|
||||||
|
|
||||||
|
| Не делать | Вместо |
|
||||||
|
|-----------|--------|
|
||||||
|
| `launch-galaxy.sh` / Galaxy CEF для JA3 | `run-ja3.sh` |
|
||||||
|
| Whisky Run **`JA3.exe`** без CWD | `run-ja3.sh` (`start /d`) |
|
||||||
|
| Дважды подряд `run-ja3.sh` без reset при живом JA3 | `reset-ja3-whisky.sh` |
|
||||||
|
| Galaxy web-stub для JA3 | offline innoextract |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Быстрые команды
|
||||||
|
|
||||||
| Действие | Команда |
|
| Действие | Команда |
|
||||||
|----------|---------|
|
|----------|---------|
|
||||||
| **Запуск** | `bash ~/code/local_machine/scripts/games/gog/run-ja3-crossover.sh` |
|
| **Запуск** | `bash ~/code/local_machine/scripts/games/gog/run-ja3.sh` |
|
||||||
| **Стоп / reset Wine** | `bash ~/code/local_machine/scripts/games/gog/reset-ja3-crossover.sh` |
|
| **Стоп** | `bash ~/code/local_machine/scripts/games/gog/reset-ja3-whisky.sh` |
|
||||||
| **Стоп всё GOG/Wine** | `bash ~/code/local_machine/scripts/games/gog/emergency-stop.sh` |
|
| Стоп всё GOG/Wine | `bash ~/code/local_machine/scripts/games/gog/emergency-stop.sh` |
|
||||||
| **Первичная настройка bottle** | `bash ~/code/local_machine/scripts/games/gog/setup-ja3-crossover.sh` |
|
| Проверить процесс | `pgrep -fl 'JA3\.exe'` |
|
||||||
| **Фикс мыши** | `bash ~/code/local_machine/scripts/games/gog/fix-ja3-crossover-mouse.sh` |
|
| Обход swap | `JA3_IGNORE_SWAP=1 bash …/run-ja3.sh` |
|
||||||
| Swap «залип» 2–4 GB, Wine нет | просто `run-ja3-crossover.sh` (warn) |
|
|
||||||
| Swap + Wine/JA3 живы ≥ 1200 MB | `reset-ja3-crossover.sh` → reboot |
|
|
||||||
| Swap ≥ 4096 MB без Wine | reboot Mac |
|
|
||||||
| Обход swap | `JA3_IGNORE_SWAP=1 bash …/run-ja3-crossover.sh` |
|
|
||||||
| Профиль мыши | `JA3_MOUSE_PROFILE=legacy\|retina-lite\|retina` + fix + reset + run |
|
|
||||||
|
|
||||||
**Полный цикл перезапуска:**
|
**Полный цикл:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bash ~/code/local_machine/scripts/games/gog/reset-ja3-crossover.sh
|
bash ~/code/local_machine/scripts/games/gog/reset-ja3-whisky.sh
|
||||||
bash ~/code/local_machine/scripts/games/gog/run-ja3-crossover.sh
|
bash ~/code/local_machine/scripts/games/gog/run-ja3.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 8. Ссылки
|
## 7. Ссылки
|
||||||
|
|
||||||
- [Gcenx — нет D3DMetal в packages](https://github.com/Gcenx/macOS_Wine_builds/issues/97)
|
- [Gcenx — нет D3DMetal в packages](https://github.com/Gcenx/macOS_Wine_builds/issues/97)
|
||||||
- [CrossOver — D3DMetal advanced settings](https://support.codeweavers.com/miscellanous/advanced-settings-in-crossover-mac-26)
|
|
||||||
- [Whisky — GPU / GPTK tracking](https://github.com/Whisky-App/Whisky/issues/124)
|
- [Whisky — GPU / GPTK tracking](https://github.com/Whisky-App/Whisky/issues/124)
|
||||||
- [Proton JA3 — graphics / LocalStorage](https://github.com/ValveSoftware/Proton/issues/7039) (Linux; отражения Off/Low — аналог для Wine при других GPU)
|
- [Proton JA3 — graphics](https://github.com/ValveSoftware/Proton/issues/7039)
|
||||||
|
|||||||
@@ -30,9 +30,9 @@ GOG web-stub: bottle **`GOG-Install`** (`scripts/games/gog/bottle.env`) — **н
|
|||||||
| **GOG Galaxy: окна нет**, скрипт OK | offline installer JA3; Galaxy — best effort | [§ GOG Galaxy — окно](#gog-galaxy-окно-не-открывается) · [GOG_GALAXY_7H_RCA.md](GOG_GALAXY_7H_RCA.md) |
|
| **GOG Galaxy: окна нет**, скрипт OK | offline installer JA3; Galaxy — best effort | [§ GOG Galaxy — окно](#gog-galaxy-окно-не-открывается) · [GOG_GALAXY_7H_RCA.md](GOG_GALAXY_7H_RCA.md) |
|
||||||
| GOG Galaxy → **swap**, Mac «встал» | `gog/emergency-stop.sh` → перезагрузка | [GOG_GALAXY_7H_RCA.md](GOG_GALAXY_7H_RCA.md) § Swap |
|
| GOG Galaxy → **swap**, Mac «встал» | `gog/emergency-stop.sh` → перезагрузка | [GOG_GALAXY_7H_RCA.md](GOG_GALAXY_7H_RCA.md) § Swap |
|
||||||
| GOG stub: «запустил, окна нет» | **Cmd+Tab** → `GOG_Galaxy_*.exe` / `wine64` | [§ GOG — проверка успеха](#gog-web-stub-отдельный-bottle) |
|
| GOG stub: «запустил, окна нет» | **Cmd+Tab** → `GOG_Galaxy_*.exe` / `wine64` | [§ GOG — проверка успеха](#gog-web-stub-отдельный-bottle) |
|
||||||
| **JA3: Failed to initialize graphics subsystem** | CrossOver D3DMetal, не Whisky | [JA3_RUNBOOK.md](JA3_RUNBOOK.md) §2–4 |
|
| **JA3: Failed to initialize graphics subsystem** | GPTK/D3DMetal в Whisky или D3D11 fallback | [JA3_RUNBOOK.md](JA3_RUNBOOK.md) §2 |
|
||||||
| **JA3: курсор не ниже середины / смещение клика** | профиль мыши **legacy** vs retina | [JA3_RUNBOOK.md](JA3_RUNBOOK.md) §9 |
|
| **JA3: `run-ja3.sh` — сразу `%`, окна нет** | задержка cold start + `emergency-stop` — **норма** | [§ JA3 — запуск](#ja3--запуск-whisky) |
|
||||||
| **JA3 без Galaxy** | install → Whisky; **запуск → CrossOver** | [JA3_RUNBOOK.md](JA3_RUNBOOK.md) |
|
| **JA3: повторный запуск не идёт** | swap-guard + JA3/Wine ещё живы | `reset-ja3-whisky.sh` |
|
||||||
| Установить через web-stub | только GalaxySetup (ломается в Wine) | [§ GOG web-stub](#gog-web-stub-отдельный-bottle) |
|
| Установить через web-stub | только GalaxySetup (ломается в Wine) | [§ GOG web-stub](#gog-web-stub-отдельный-bottle) |
|
||||||
| `fork failed`, Mac «встал», swap 20+ GB | `winedbg` / Steam assert loop → § Swap | [§ Swap и winedbg](#захламление-swap-и-утечка-winedbg) |
|
| `fork failed`, Mac «встал», swap 20+ GB | `winedbg` / Steam assert loop → § Swap | [§ Swap и winedbg](#захламление-swap-и-утечка-winedbg) |
|
||||||
| «20 GB съело» после GOG | обычно **не** stub — swap + дампы Steam | [§ Swap](#захламление-swap-и-утечка-winedbg) · [§ GOG](#gog-web-stub-отдельный-bottle) |
|
| «20 GB съело» после GOG | обычно **не** stub — swap + дампы Steam | [§ Swap](#захламление-swap-и-утечка-winedbg) · [§ GOG](#gog-web-stub-отдельный-bottle) |
|
||||||
@@ -110,6 +110,9 @@ GOG web-stub: bottle **`GOG-Install`** (`scripts/games/gog/bottle.env`) — **н
|
|||||||
| Только **`install-corefonts`**, без **gdiplus** | `.ttf` есть, лог всё равно `FontFamilyNotFound` | оба скрипта + порядок ниже |
|
| Только **`install-corefonts`**, без **gdiplus** | `.ttf` есть, лог всё равно `FontFamilyNotFound` | оба скрипта + порядок ниже |
|
||||||
| **`setup-wine-bottle.sh`** для GOG web-stub | DWrite/Steam-реестр, **нет** gdiplus | **`gog/setup-bottle.sh`** |
|
| **`setup-wine-bottle.sh`** для GOG web-stub | DWrite/Steam-реестр, **нет** gdiplus | **`gog/setup-bottle.sh`** |
|
||||||
| **`setup-gog-bottle.sh`** (HoMM) для JA3 | устаревшая обёртка | **`gog/setup-bottle.sh`** |
|
| **`setup-gog-bottle.sh`** (HoMM) для JA3 | устаревшая обёртка | **`gog/setup-bottle.sh`** |
|
||||||
|
| **Whisky** Run `JA3.exe` в Whisky без `run-ja3.sh` | `dxgi.dll not found`, CWD/autorun | **`run-ja3.sh`** |
|
||||||
|
| Считать мгновенный `%` после `run-ja3.sh` сбоем | `wine start` не блокирует Terminal | **Cmd+Tab** → `JA3.exe`; ждать до ~60 с |
|
||||||
|
| Два `run-ja3.sh` подряд без reset | swap ≥1200 MB + живой JA3 | `reset-ja3-whisky.sh` |
|
||||||
| **winetricks corefonts** из Whisky GUI | 404 на CDN Microsoft | SourceForge в **`gog/install-corefonts.sh`**; macOS Fonts |
|
| **winetricks corefonts** из Whisky GUI | 404 на CDN Microsoft | SourceForge в **`gog/install-corefonts.sh`**; macOS Fonts |
|
||||||
| **Debian-only** URL `msttcorefonts` | 404 | primary: `downloads.sourceforge.net/corefonts/…` |
|
| **Debian-only** URL `msttcorefonts` | 404 | primary: `downloads.sourceforge.net/corefonts/…` |
|
||||||
| **`winetricks liberation`** как единственный шаг | мало гарантий для VGUI/.NET | macOS + corefonts + профиль DLL |
|
| **`winetricks liberation`** как единственный шаг | мало гарантий для VGUI/.NET | macOS + corefonts + профиль DLL |
|
||||||
@@ -713,7 +716,45 @@ A/B CEF: `GOG_CEF_PROFILE=steam bash …/launch-galaxy-ui.sh` (добавляе
|
|||||||
| Смотреть только Whisky, не Cmd+Tab | окно Wine **вне** главного окна Whisky |
|
| Смотреть только Whisky, не Cmd+Tab | окно Wine **вне** главного окна Whisky |
|
||||||
| Запуск из `~/code/local_machine` без `cd drive_c` | `launch-galaxy.sh` сам ставит cwd в `drive_c` |
|
| Запуск из `~/code/local_machine` без `cd drive_c` | `launch-galaxy.sh` сам ставит cwd в `drive_c` |
|
||||||
|
|
||||||
**JA3 на Mac:** установка — offline backup + `install-ja3-innoextract.sh` (Whisky GOG-Install). **Запуск — CrossOver D3DMetal:** `setup-ja3-crossover.sh` + `run-ja3-crossover.sh`. Whisky `run-ja3.sh` **не** даёт рабочую D3D12. Runbook: [JA3_RUNBOOK.md](JA3_RUNBOOK.md).
|
**JA3 на Mac:** установка — offline backup + `install-ja3-innoextract.sh` (Whisky GOG-Install). **Запуск:** `run-ja3.sh`. Runbook: [JA3_RUNBOOK.md](JA3_RUNBOOK.md).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## JA3 — запуск (Whisky)
|
||||||
|
|
||||||
|
**Канон:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash ~/code/local_machine/scripts/games/gog/run-ja3.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
`run-ja3.sh` запускает JA3 в bottle **GOG-Install** (Whisky). CrossOver **удалён** (2026-06).
|
||||||
|
|
||||||
|
### «Не пускает» vs «задержка»
|
||||||
|
|
||||||
|
| Что видите | Это ошибка? | Действие |
|
||||||
|
|------------|-------------|----------|
|
||||||
|
| Строки «Запуск JA3…» и сразу `%` | **Нет** — `wine start` не держит Terminal | Подождать 15–60 с, **Cmd+Tab** → `JA3.exe` |
|
||||||
|
| Пауза 20–40 с **до** строк «Запуск JA3…» | **Нет** — `emergency-stop` + `sleep 2` | Норма при каждом запуске |
|
||||||
|
| `❌ Swap … Wine/JA3 ещё работают` | **Да** — повторный запуск при живой игре | `reset-ja3-whisky.sh`, затем снова `run-ja3.sh` |
|
||||||
|
| Окна нет >60 с, `pgrep JA3` пусто | **Да** | Лог в `…/GOG-Install/…/AppData/Roaming/Jagged Alliance 3/logs/JA3.exe-*.log` |
|
||||||
|
|
||||||
|
### Проверка
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pgrep -fl 'JA3\.exe'
|
||||||
|
ls -t ~/Library/Containers/com.franke.Whisky/Bottles/*/drive_c/users/*/AppData/Roaming/Jagged\ Alliance\ 3/logs/*.log 2>/dev/null | head -1 | xargs tail -20
|
||||||
|
sysctl vm.swapusage
|
||||||
|
```
|
||||||
|
|
||||||
|
### Антипаттерны (JA3 запуск)
|
||||||
|
|
||||||
|
| ❌ | ✅ |
|
||||||
|
|----|-----|
|
||||||
|
| Whisky Run **`JA3.exe`** без CWD | `run-ja3.sh` (`start /d`) |
|
||||||
|
| Ждать блокировку Terminal | Cmd+Tab → `JA3.exe` |
|
||||||
|
| Два запуска без reset при живом JA3 | `reset-ja3-whisky.sh` между сессиями |
|
||||||
|
| CrossOver / `run-ja3-crossover.sh` | удалено — только `run-ja3.sh` |
|
||||||
|
|
||||||
### Setup: красный X, пустое окно, gdi32 (RCA 2026-05-28)
|
### Setup: красный X, пустое окно, gdi32 (RCA 2026-05-28)
|
||||||
|
|
||||||
@@ -959,4 +1000,4 @@ pkill -9 winedbg; pkill -9 wineserver
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*Последняя сверка: 2026-05-28 (§ шрифты: сводка антипаттернов Steam dwrite / GOG gdiplus; GOG-Install stub OK; GalaxySetup → gdi32) · Whisky 3 · WhiskyWine 11*
|
*Последняя сверка: 2026-06-17 (CrossOver удалён; JA3 только Whisky) · 2026-05-28 (шрифты Steam dwrite / GOG gdiplus) · Whisky 3*
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
| **GOG Galaxy (лаунчер)** | Galaxy 2.0 | `start.sh gog-install` или `gog/install-galaxy-extract.sh` | `gog` |
|
| **GOG Galaxy (лаунчер)** | Galaxy 2.0 | `start.sh gog-install` или `gog/install-galaxy-extract.sh` | `gog` |
|
||||||
| **GOG web-stub** | `GOG_Galaxy_*.exe` | Только bottle `gog/` — [gog/README.md](../../scripts/games/gog/README.md) | `gog` |
|
| **GOG web-stub** | `GOG_Galaxy_*.exe` | Только bottle `gog/` — [gog/README.md](../../scripts/games/gog/README.md) | `gog` |
|
||||||
| **Офлайн setup .exe** | backup с gog.com | Скопировать в `drive_c/`, запустить установщик | `plain` или `gog` |
|
| **Офлайн setup .exe** | backup с gog.com | Скопировать в `drive_c/`, запустить установщик | `plain` или `gog` |
|
||||||
| **GOG multipart + innoextract** | JA3 offline backup | `gog/install-ja3-innoextract.sh` — [JA3 runbook](JA3_RUNBOOK.md) | **CrossOver:** `run-ja3-crossover.sh` |
|
| **GOG multipart + innoextract** | JA3 offline backup | `gog/install-ja3-innoextract.sh` — [JA3 runbook](JA3_RUNBOOK.md) | `gog/run-ja3.sh` |
|
||||||
| **.NET WinForms installer** | web-stub, мастера GOG | **`gog/install-gdiplus.sh`** + corefonts | `gog` |
|
| **.NET WinForms installer** | web-stub, мастера GOG | **`gog/install-gdiplus.sh`** + corefonts | `gog` |
|
||||||
| **CEF (Steam/GOG UI)** | Steam.exe, GalaxyClient | CEF-флаги в `config.sh` / `gog/config.sh` | `steam` / `gog` |
|
| **CEF (Steam/GOG UI)** | Steam.exe, GalaxyClient | CEF-флаги в `config.sh` / `gog/config.sh` | `steam` / `gog` |
|
||||||
| **DX11 игра (Unity и т.д.)** | Olden Era | `install-dxvk-macos.sh` | `game` |
|
| **DX11 игра (Unity и т.д.)** | Olden Era | `install-dxvk-macos.sh` | `game` |
|
||||||
@@ -97,7 +97,7 @@ bash …/run-wine-exe.sh --background --log /tmp/my-app.log --profile plain 'C:\
|
|||||||
| Место на диске | `bash …/start.sh disk` |
|
| Место на диске | `bash …/start.sh disk` |
|
||||||
| GOG bottle: клиент | `bash …/gog/launch-galaxy.sh` |
|
| GOG bottle: клиент | `bash …/gog/launch-galaxy.sh` |
|
||||||
| GOG bottle: JA3 установка | `bash …/gog/install-ja3-innoextract.sh` |
|
| GOG bottle: JA3 установка | `bash …/gog/install-ja3-innoextract.sh` |
|
||||||
| GOG bottle: JA3 запуск | `bash …/gog/run-ja3-crossover.sh` — [JA3_RUNBOOK.md](JA3_RUNBOOK.md) |
|
| GOG bottle: JA3 запуск | `bash …/gog/run-ja3.sh` — [JA3_RUNBOOK.md](JA3_RUNBOOK.md) |
|
||||||
|
|
||||||
Полный список: `bash …/start.sh` без аргументов.
|
Полный список: `bash …/start.sh` без аргументов.
|
||||||
|
|
||||||
@@ -147,7 +147,7 @@ export WINEMSYNC=1 WINEESYNC=1
|
|||||||
| **Steam** | HoMM-OldenEra | `start.sh steam-ui` | Не параллельно с Steam.app |
|
| **Steam** | HoMM-OldenEra | `start.sh steam-ui` | Не параллельно с Steam.app |
|
||||||
| **HoMM Olden Era** | HoMM-OldenEra | `start.sh play` | Не Play в Steam UI; нужен DXVK — §7 |
|
| **HoMM Olden Era** | HoMM-OldenEra | `start.sh play` | Не Play в Steam UI; нужен DXVK — §7 |
|
||||||
| **GOG Galaxy 2.0** | HoMM-OldenEra | `start.sh gog` | Логин в Wine — best effort |
|
| **GOG Galaxy 2.0** | HoMM-OldenEra | `start.sh gog` | Логин в Wine — best effort |
|
||||||
| **Jagged Alliance 3** | GOG-Install + CrossOver **JA3-GOG** | `gog/run-ja3-crossover.sh` | Установка: Whisky `install-ja3-innoextract.sh` ([runbook](JA3_RUNBOOK.md)) |
|
| **Jagged Alliance 3** | GOG-Install (Whisky) | `gog/run-ja3.sh` | Установка: `install-ja3-innoextract.sh` ([runbook](JA3_RUNBOOK.md)) |
|
||||||
| **GOG Galaxy 2.0** | GOG-Install | `gog/launch-galaxy.sh` | Best effort; JA3 — **не** через Galaxy на этом Mac |
|
| **GOG Galaxy 2.0** | GOG-Install | `gog/launch-galaxy.sh` | Best effort; JA3 — **не** через Galaxy на этом Mac |
|
||||||
| **Любой новый .exe** | свой / общий | `run-wine-exe.sh` | §2.1 |
|
| **Любой новый .exe** | свой / общий | `run-wine-exe.sh` | §2.1 |
|
||||||
|
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ export_wine_env
|
|||||||
1. Пять файлов в **`~/Games/`**: `setup_jagged_alliance_3_1.5.2_(80730).exe` + `-1.bin` … `-4.bin`.
|
1. Пять файлов в **`~/Games/`**: `setup_jagged_alliance_3_1.5.2_(80730).exe` + `-1.bin` … `-4.bin`.
|
||||||
2. Bottle **GOG-Install** (`gog/bottle.env`).
|
2. Bottle **GOG-Install** (`gog/bottle.env`).
|
||||||
3. `bash …/gog/install-ja3-innoextract.sh` — распаковка в `drive_c/GOG Games/Jagged Alliance 3/`, `.bin` удаляются по мере чтения, после успеха — все архивы в `~/Games` (~15 GB).
|
3. `bash …/gog/install-ja3-innoextract.sh` — распаковка в `drive_c/GOG Games/Jagged Alliance 3/`, `.bin` удаляются по мере чтения, после успеха — все архивы в `~/Games` (~15 GB).
|
||||||
4. Запуск: `bash …/gog/run-ja3-crossover.sh` (swap guard: см. [JA3_RUNBOOK.md](JA3_RUNBOOK.md) §4, §10).
|
4. Запуск: `bash …/gog/run-ja3.sh` (swap guard: см. [JA3_RUNBOOK.md](JA3_RUNBOOK.md) §1, §6).
|
||||||
|
|
||||||
Полный runbook: [JA3_MAC_WITHOUT_GALAXY.md](JA3_MAC_WITHOUT_GALAXY.md).
|
Полный runbook: [JA3_MAC_WITHOUT_GALAXY.md](JA3_MAC_WITHOUT_GALAXY.md).
|
||||||
|
|
||||||
|
|||||||
3
docs/linux/fedora/MBP_INTEL_BCM4322_WIFI_RUNBOOK.md
Normal file
3
docs/linux/fedora/MBP_INTEL_BCM4322_WIFI_RUNBOOK.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Перенесено
|
||||||
|
|
||||||
|
Документация и скрипты для Fedora на старом MacBook Pro Intel — в **[../old_mac/README.md](../old_mac/README.md)**.
|
||||||
215
docs/mac/DISPLAY_FREEZE_RUNBOOK.md
Normal file
215
docs/mac/DISPLAY_FREEZE_RUNBOOK.md
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
# MacBook Pro M1 — зависания после замены матрицы
|
||||||
|
|
||||||
|
**Контекст:** заменена матрица (Built-in Liquid Retina XDR). После ремонта — повторяющиеся полные зависания системы.
|
||||||
|
**Инцидент:** 2026-06-16, ~4 зависания за час (21:31–21:43).
|
||||||
|
**Проверено:** 2026-06-16, логи `/Library/Logs/DiagnosticReports/`, `log show`, `last reboot`.
|
||||||
|
|
||||||
|
См. также: [README.md](./README.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Симптом
|
||||||
|
|
||||||
|
| Что видит пользователь | Что в логах |
|
||||||
|
|------------------------|-------------|
|
||||||
|
| Экран и ввод «замирают», курсор не двигается | Нет записей в unified log на время freeze (дыра в логах) |
|
||||||
|
| Помогает только **удержание кнопки питания** | `btn_rst` / `finger_reset` в `forceReset-full-*.diag` |
|
||||||
|
| Зависания повторяются **сразу после перезагрузки** (через 2–9 мин) | Аптайм в отчётах: 155 с, 537 с |
|
||||||
|
| Не kernel panic с диалогом «перезагрузить» | Нет свежих `panic-full-*.panic` за 16.06; только `forceReset` |
|
||||||
|
|
||||||
|
Это **hard lockup** (полная неотзывчивость SoC), а не обычный краш приложения.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Хронология 2026-06-16
|
||||||
|
|
||||||
|
| Время | Событие | Аптайм до freeze |
|
||||||
|
|-------|---------|------------------|
|
||||||
|
| ~19:19 | Загрузка (сессия до первого сбоя) | — |
|
||||||
|
| 21:24–21:26 | Telegram: отчёт `cpu_resource` (~55% CPU за 3 мин) | ~2 ч |
|
||||||
|
| **21:31** | `forceReset-full-2026-06-16-213115` · `btn_rst` | **~7921 с (~2 ч 12 мин)** |
|
||||||
|
| **21:34** | `forceReset-full-2026-06-16-213425` · `btn_rst` | **~155 с (~2.5 мин)** |
|
||||||
|
| 21:34–21:37 | `deleted` (CacheDelete): `cpu_resource` (~52% CPU) | после 2-го reboot |
|
||||||
|
| **21:43** | `forceReset-full-2026-06-16-214334` · `btn_rst` | **~537 с (~9 мин)** |
|
||||||
|
|
||||||
|
`last reboot`:
|
||||||
|
|
||||||
|
```
|
||||||
|
reboot Tue Jun 16 21:43
|
||||||
|
reboot Tue Jun 16 21:34
|
||||||
|
reboot Tue Jun 16 21:31
|
||||||
|
```
|
||||||
|
|
||||||
|
В логах — **пропуск ~18 мин** (21:33 → 21:51): пока система зависла, запись остановилась.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. RCA — что зафиксировано в отчётах
|
||||||
|
|
||||||
|
### 3.1 Тип сбоя: принудительный reset
|
||||||
|
|
||||||
|
Все три отчёта за 16.06:
|
||||||
|
|
||||||
|
```
|
||||||
|
panic(cpu N caller ...): btn_rst
|
||||||
|
Debugger message: panic
|
||||||
|
Boot faults: btn_rst, finger_reset, force_off (в ResetCounter)
|
||||||
|
```
|
||||||
|
|
||||||
|
`btn_rst` = ядро зафиксировало сброс **кнопкой питания**, когда система уже не отвечала. Это не программный panic с stack trace приложения.
|
||||||
|
|
||||||
|
Файлы:
|
||||||
|
|
||||||
|
- `/Library/Logs/DiagnosticReports/forceReset-full-2026-06-16-213115.0002.diag`
|
||||||
|
- `/Library/Logs/DiagnosticReports/forceReset-full-2026-06-16-213425.0002.diag`
|
||||||
|
- `/Library/Logs/DiagnosticReports/forceReset-full-2026-06-16-214334.0002.diag`
|
||||||
|
- `/Library/Logs/DiagnosticReports/ResetCounter-2026-06-16-213129.diag` (и 213438, 214346)
|
||||||
|
|
||||||
|
### 3.2 Главный подозреваемый: WindowServer (графический стек)
|
||||||
|
|
||||||
|
Снимок процессов **на момент зависания** (поле `systemTimeTask`):
|
||||||
|
|
||||||
|
| Freeze | Аптайм | WindowServer CPU time | Паттерн потоков |
|
||||||
|
|--------|--------|----------------------|-----------------|
|
||||||
|
| 21:31 | ~2 ч 12 мин | **714 с** | потоки ждут `semaphore port ... owned by pid` **самого WindowServer** |
|
||||||
|
| 21:34 | ~2.5 мин | **15 с** | то же — deadlock на semaphore |
|
||||||
|
| 21:43 | ~9 мин | **49 с** | то же — deadlock на semaphore |
|
||||||
|
|
||||||
|
WindowServer — процесс отрисовки всего UI (SkyLight). Потоки, ждущие semaphore у того же PID, — типичный **deadlock в графическом конвейере**.
|
||||||
|
|
||||||
|
Рядом в снимках присутствуют процессы дисплейного стека:
|
||||||
|
|
||||||
|
- `corebrightnessd` — яркость / подсветка
|
||||||
|
- `IOMFB_bics_daemon` — framebuffer (IOMFB)
|
||||||
|
- `backboardd` — события ввода / дисплей
|
||||||
|
|
||||||
|
### 3.3 Что **не** найдено в открытых логах
|
||||||
|
|
||||||
|
Поиск за 3 ч по `DCP`, `IOMFB`, `CLCD`, `backlight`, `GPU reset`, `panel`, `LCD`:
|
||||||
|
|
||||||
|
- **Нет** явных ошибок драйвера дисплея или DCP
|
||||||
|
- Только штатные записи (`mobileassetd`, `backlightservices`, уведомления)
|
||||||
|
|
||||||
|
Apple часто **не пишет** аппаратные ошибки шлейфа/матрицы в открытый unified log. Отсутствие строк не опровергает аппаратную причину.
|
||||||
|
|
||||||
|
### 3.4 Дополнительная нагрузка (усиливающие факторы)
|
||||||
|
|
||||||
|
| Процесс | Когда | Наблюдение |
|
||||||
|
|---------|-------|------------|
|
||||||
|
| **Telegram** | 21:24–21:26 | `cpu_resource`: ~55% CPU за 162 с |
|
||||||
|
| **deleted** (CacheDelete) | 21:34–21:37 | `cpu_resource`: ~52% CPU, 88 с после boot |
|
||||||
|
| **mds** / Spotlight | после каждого reboot | активная индексация (`mdworker_shared`) |
|
||||||
|
| **Память** | на момент проверки | 16 GB почти заняты, ~7.8 GB в compressor, свободно ~140 MB |
|
||||||
|
|
||||||
|
Высокая нагрузка и давление на память **усиливают** нестабильность, но паттерн WindowServer-deadlock + быстрые повторы после reboot указывают на проблему **графики/дисплея**, а не только на фоновые процессы.
|
||||||
|
|
||||||
|
### 3.5 История до 16.06 (система нестабильна несколько дней)
|
||||||
|
|
||||||
|
| Период | Тип отчётов | Характер |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| 10–11.06 | `shutdown_stall` | зависание при выключении |
|
||||||
|
| 12–14.06 | `panic-full` + `shutdown_stall` | `Wake transition timed out after 35 seconds` · suspected: `com.apple.driver.AppleSEPManager` |
|
||||||
|
| 15.06 | `forceReset` (21:42) + `shutdown_stall` | тот же `btn_rst` |
|
||||||
|
| 16.06 | 3× `forceReset` за час | WindowServer deadlock |
|
||||||
|
|
||||||
|
До замены матрицы уже были сбои power management (SEP / wake). После ремонта доминирует другой профиль: **GUI freeze через WindowServer**, в том числе через несколько минут после загрузки.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Связь с заменой матрицы
|
||||||
|
|
||||||
|
Прямых строк «ошибка шлейфа» в логах нет. Косвенные признаки, согласующиеся с ремонтом дисплея:
|
||||||
|
|
||||||
|
1. **WindowServer стабильно уходит в deadlock** на всех трёх снимках
|
||||||
|
2. В стеке рядом — `corebrightnessd`, `IOMFB_bics_daemon`
|
||||||
|
3. Зависания **сразу после reboot** (2.5 и 9 мин) — типично для драйвера/железа дисплея, а не для «прогрева» одного приложения
|
||||||
|
4. Полный lockup (`btn_rst`) без kernel panic — возможен при зависании GPU/DCP-конвейера
|
||||||
|
|
||||||
|
**Вероятные аппаратные причины (для сервиса):**
|
||||||
|
|
||||||
|
- плохой контакт **шлейфа матрицы** (eDP/LVDS)
|
||||||
|
- повреждение или неправильная укладка **кабеля дисплея**
|
||||||
|
- несовместимая или дефектная **матрица** для `MacBookPro18,1` (Liquid Retina XDR)
|
||||||
|
- ошибка сборки: винты, заземление, T-Con / подсветка
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Действия
|
||||||
|
|
||||||
|
### 5.1 Сервис (приоритет)
|
||||||
|
|
||||||
|
Вернуть в сервис с этим runbook. Попросить проверить:
|
||||||
|
|
||||||
|
1. Посадку шлейфа матрицы и display cable на обоих концах
|
||||||
|
2. Отсутствие перекоса / залома шлейфа при закрытии крышки
|
||||||
|
3. Совместимость матрицы с **MacBookPro18,1** (Liquid Retina XDR, не «похожая» панель)
|
||||||
|
4. Корректность сборки подсветки и T-Con
|
||||||
|
|
||||||
|
### 5.2 Диагностика на Mac
|
||||||
|
|
||||||
|
**Apple Diagnostics** (нативная):
|
||||||
|
|
||||||
|
1. Выключить Mac
|
||||||
|
2. Зажать питание → «Параметры» → «Диагностика»
|
||||||
|
|
||||||
|
**Safe Mode** (отсечь сторонние драйверы/агенты):
|
||||||
|
|
||||||
|
1. Выключить → зажать питание → «Продолжить с безопасным режимом»
|
||||||
|
2. Если в Safe Mode стабильно час+ — сильнее аргумент в пользу софта/агентов; если снова freeze — железо/драйвер дисплея
|
||||||
|
|
||||||
|
**Минимальная нагрузка после reboot:**
|
||||||
|
|
||||||
|
- не открывать Cursor, Brave, Telegram сразу после загрузки
|
||||||
|
- проверить, воспроизводится ли freeze на пустом рабочем столе
|
||||||
|
|
||||||
|
### 5.3 Мониторинг
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# последние force reset
|
||||||
|
ls -lt /Library/Logs/DiagnosticReports/forceReset-full-* | head -5
|
||||||
|
|
||||||
|
# причина в заголовке отчёта
|
||||||
|
head -12 /Library/Logs/DiagnosticReports/forceReset-full-*.0002.diag | \
|
||||||
|
grep -o 'panic(cpu[^\\]*'
|
||||||
|
|
||||||
|
# ошибки WindowServer
|
||||||
|
log stream --predicate 'process == "WindowServer"' --level error
|
||||||
|
|
||||||
|
# перезагрузки
|
||||||
|
last reboot | head -10
|
||||||
|
```
|
||||||
|
|
||||||
|
После следующего зависания **не перезагружать сразу** (если возможно подождать 1–2 мин) — иногда успевает дописаться больше в `/Library/Logs/DiagnosticReports/`. На практике при hard lockup это редко помогает; основные данные уже в `forceReset-full`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Краткий вывод
|
||||||
|
|
||||||
|
| Вопрос | Ответ |
|
||||||
|
|--------|-------|
|
||||||
|
| Это kernel panic? | Нет (16.06). Это **hard lockup** → сброс кнопкой (`btn_rst`) |
|
||||||
|
| Сколько зафиксировано 16.06? | **3** отчёта `forceReset`; пользователь сообщал о ~4 зависаниях |
|
||||||
|
| Что зависало? | **WindowServer** — deadlock, графический стек |
|
||||||
|
| Есть ли ошибки DCP/шлейфа в логах? | **Нет** в открытом unified log |
|
||||||
|
| Главная рекомендация | **Перепроверка шлейфа и сборки дисплея в сервисе** |
|
||||||
|
| Была ли нестабильность раньше? | Да, с 10–11.06 (`shutdown_stall`, SEP wake timeout) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Ссылки на файлы отчётов
|
||||||
|
|
||||||
|
```
|
||||||
|
/Library/Logs/DiagnosticReports/forceReset-full-2026-06-16-213115.0002.diag
|
||||||
|
/Library/Logs/DiagnosticReports/forceReset-full-2026-06-16-213425.0002.diag
|
||||||
|
/Library/Logs/DiagnosticReports/forceReset-full-2026-06-16-214334.0002.diag
|
||||||
|
/Library/Logs/DiagnosticReports/ResetCounter-2026-06-16-213129.diag
|
||||||
|
/Library/Logs/DiagnosticReports/ResetCounter-2026-06-16-213438.diag
|
||||||
|
/Library/Logs/DiagnosticReports/ResetCounter-2026-06-16-214346.diag
|
||||||
|
/Library/Logs/DiagnosticReports/Telegram_2026-06-16-212645_Eternals.cpu_resource.diag
|
||||||
|
/Library/Logs/DiagnosticReports/deleted_2026-06-16-213726_Eternals.cpu_resource.diag
|
||||||
|
|
||||||
|
# более ранние (контекст)
|
||||||
|
/Library/Logs/DiagnosticReports/panic-full-2026-06-14-115455.0002.panic # Wake transition / SEP
|
||||||
|
/Library/Logs/DiagnosticReports/panic-full-2026-06-13-155145.0002.panic
|
||||||
|
/Library/Logs/DiagnosticReports/forceReset-full-2026-06-15-194242.0002.diag
|
||||||
|
```
|
||||||
42
docs/mac/README.md
Normal file
42
docs/mac/README.md
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
# Mac — основной MacBook (Apple Silicon)
|
||||||
|
|
||||||
|
Контур для **MacBook Pro M1 Pro** (`MacBookPro18,1`): диагностика, нестабильность, дисплей.
|
||||||
|
|
||||||
|
**Проверено:** 2026-06-16
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Документы
|
||||||
|
|
||||||
|
| Документ | Назначение |
|
||||||
|
|----------|------------|
|
||||||
|
| **[DISPLAY_FREEZE_RUNBOOK.md](./DISPLAY_FREEZE_RUNBOOK.md)** | Зависания после замены матрицы: RCA по логам, хронология, действия |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Железо (справка)
|
||||||
|
|
||||||
|
| Параметр | Значение |
|
||||||
|
|----------|----------|
|
||||||
|
| Модель | MacBook Pro 14" (`MacBookPro18,1`) |
|
||||||
|
| Чип | Apple M1 Pro, 10 ядер, 16 GB RAM |
|
||||||
|
| Дисплей | Built-in Liquid Retina XDR, 3456×2234 |
|
||||||
|
| ОС | macOS 15.3.1 (24D70) |
|
||||||
|
| Серийник | X47KCRG26W |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Быстрая диагностика зависания
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# последние принудительные перезагрузки (кнопка питания)
|
||||||
|
ls -lt /Library/Logs/DiagnosticReports/forceReset-full-* | head -5
|
||||||
|
|
||||||
|
# история перезагрузок
|
||||||
|
last reboot | head -10
|
||||||
|
|
||||||
|
# ошибки WindowServer в реальном времени
|
||||||
|
log stream --predicate 'process == "WindowServer"' --level error
|
||||||
|
```
|
||||||
|
|
||||||
|
Подробно: [DISPLAY_FREEZE_RUNBOOK.md](./DISPLAY_FREEZE_RUNBOOK.md)
|
||||||
237
docs/old_mac/BLUETOOTH_FILE_TRANSFER.md
Normal file
237
docs/old_mac/BLUETOOTH_FILE_TRANSFER.md
Normal file
@@ -0,0 +1,237 @@
|
|||||||
|
# Передача файлов Mac → Fedora (Bluetooth)
|
||||||
|
|
||||||
|
**Откуда:** этот Mac (Apple Silicon / основной)
|
||||||
|
**Куда:** MacBook Pro Intel с Fedora 43 (устройство Bluetooth: **fedora**, `60:FB:42:7D:2D:66`)
|
||||||
|
**Проверено:** 2026-06-16
|
||||||
|
|
||||||
|
Связанные документы: [README.md](./README.md), [RUNBOOK.md](./RUNBOOK.md) (Wi‑Fi BCM4322).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Быстрый путь (канон)
|
||||||
|
|
||||||
|
### Шаг 1 — Fedora: включить приём **до** отправки
|
||||||
|
|
||||||
|
Blueman (иконка Bluetooth в трее) → **«Принять файл»** / **Receive a File**.
|
||||||
|
|
||||||
|
Должен появиться диалог **«Ожидание входящего файла…»**.
|
||||||
|
Без этого Mac отправит файл, но на Fedora **ничего не произойдёт** — диалога не будет.
|
||||||
|
|
||||||
|
### Шаг 2 — Mac: отправить
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# delivery-архив Wi-Fi fix (по умолчанию)
|
||||||
|
bash ~/code/local_machine/docs/old_mac/scripts/send-to-fedora-bluetooth.sh
|
||||||
|
|
||||||
|
# любой другой файл
|
||||||
|
bash ~/code/local_machine/docs/old_mac/scripts/send-to-fedora-bluetooth.sh /path/to/file.tar.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
В окне **Bluetooth File Exchange** выбрать **fedora** → **Send** / **Отправить**.
|
||||||
|
|
||||||
|
### Шаг 3 — Fedora: проверить
|
||||||
|
|
||||||
|
Файл обычно в `~/Downloads` или `~/Bluetooth`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ls -la ~/Downloads/
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. RCA: почему «отправилось», а на Fedora тишина
|
||||||
|
|
||||||
|
| Что видели | Причина |
|
||||||
|
|------------|---------|
|
||||||
|
| AppleScript пишет «send выполнена» | macOS **не запускает** OBEX-приём на Linux автоматически |
|
||||||
|
| Окно на Mac открылось, Fedora молчит | На Fedora **не был включён** «Принять файл» |
|
||||||
|
| `bnep0` / PAN не связан с файлами | Передача файлов — **OBEX**, не PAN |
|
||||||
|
| Устройство paired, но не Connected | На Fedora: Bluetooth on, Trust Mac, оставить в зоне видимости |
|
||||||
|
|
||||||
|
**Правило:** сначала **приём на Fedora**, потом **отправка с Mac**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Предварительные условия
|
||||||
|
|
||||||
|
### Сопряжение (один раз)
|
||||||
|
|
||||||
|
**Fedora:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bluetoothctl
|
||||||
|
power on
|
||||||
|
agent on
|
||||||
|
default-agent
|
||||||
|
scan on
|
||||||
|
# найти Mac по имени, затем:
|
||||||
|
pair <MAC_ЭТОГО_MAC>
|
||||||
|
trust <MAC_ЭТОГО_MAC>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Mac:** Системные настройки → Bluetooth → подтвердить сопряжение.
|
||||||
|
|
||||||
|
### Перед каждой передачей
|
||||||
|
|
||||||
|
**Mac** — fedora в **Connected**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
system_profiler SPBluetoothDataType | grep -A6 "Connected:"
|
||||||
|
# должно быть: fedora (60:FB:42:7D:2D:66)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Fedora** — Blueman установлен:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo dnf install blueman bluez-obexd
|
||||||
|
blueman-applet &
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Подробно: Fedora (приём)
|
||||||
|
|
||||||
|
### Способ A — Blueman GUI (рекомендуется)
|
||||||
|
|
||||||
|
1. Иконка Bluetooth в трее (Blueman).
|
||||||
|
2. **Принять файл** / **Receive a File**.
|
||||||
|
3. Ждать диалог «Ожидание входящего файла…».
|
||||||
|
4. **Не закрывать** до завершения передачи.
|
||||||
|
|
||||||
|
### Способ B — скрипт-подсказка
|
||||||
|
|
||||||
|
Если скрипт уже есть на Fedora (после первой передачи или скопирован вручную):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash prepare-receive-fedora.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Скрипт напомнит про Blueman и будет ждать файл в `~/Downloads`.
|
||||||
|
Сам по себе **не заменяет** пункт «Принять файл» в Blueman (без `obexpushd`).
|
||||||
|
|
||||||
|
### Куда попадает файл
|
||||||
|
|
||||||
|
| Среда | Путь |
|
||||||
|
|-------|------|
|
||||||
|
| GNOME + Blueman | `~/Downloads` |
|
||||||
|
| KDE | `~/Downloads` или `~/Bluetooth` |
|
||||||
|
| obexpushd | каталог из `-p` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Подробно: Mac (отправка)
|
||||||
|
|
||||||
|
### Способ A — скрипт (рекомендуется)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Wi-Fi fix archive (готовый)
|
||||||
|
bash ~/code/local_machine/docs/old_mac/scripts/send-to-fedora-bluetooth.sh
|
||||||
|
|
||||||
|
# произвольный файл
|
||||||
|
bash ~/code/local_machine/docs/old_mac/scripts/send-to-fedora-bluetooth.sh ~/Desktop/myfile.tar.gz
|
||||||
|
|
||||||
|
# другое имя BT-устройства (если не «fedora»)
|
||||||
|
bash ~/code/local_machine/docs/old_mac/scripts/send-to-fedora-bluetooth.sh myfile.zip my-fedora
|
||||||
|
```
|
||||||
|
|
||||||
|
Скрипт проверяет, что **fedora** в Connected, и открывает **Bluetooth File Exchange**.
|
||||||
|
|
||||||
|
### Способ B — вручную (без скрипта)
|
||||||
|
|
||||||
|
1. Finder → файл → ПКМ → **Поделиться** → **Bluetooth**
|
||||||
|
**или** открыть `/System/Applications/Utilities/Bluetooth File Exchange.app`
|
||||||
|
2. Перетащить файл в окно / File → Send File…
|
||||||
|
3. Выбрать **fedora** → **Send**
|
||||||
|
|
||||||
|
### Способ C — из терминала (то же GUI)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
open -a "Bluetooth File Exchange" /path/to/file.tar.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
Дальше вручную выбрать **fedora** → **Send**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Что отправлять (Wi‑Fi fix)
|
||||||
|
|
||||||
|
Готовый архив для Fedora:
|
||||||
|
|
||||||
|
```text
|
||||||
|
docs/old_mac/deliverable/fedora-bcm4322-wifi-fix.tar.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
Пересобрать:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash ~/code/local_machine/docs/old_mac/scripts/build-delivery-archive.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
После приёма на Fedora:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/Downloads
|
||||||
|
tar xzf fedora-bcm4322-wifi-fix.tar.gz
|
||||||
|
cd fedora-bcm4322-wifi-fix
|
||||||
|
sudo bash install-bcm4322-firmware-fedora.sh
|
||||||
|
sudo reboot
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Диагностика
|
||||||
|
|
||||||
|
### Mac
|
||||||
|
|
||||||
|
```bash
|
||||||
|
system_profiler SPBluetoothDataType | grep -A8 "Connected:"
|
||||||
|
pgrep -lf "Bluetooth File Exchange"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Fedora
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bluetoothctl devices
|
||||||
|
bluetoothctl info 60:FB:42:7D:2D:66 # MAC этого Mac — подставить свой
|
||||||
|
systemctl --user status obex
|
||||||
|
journalctl -b -u bluetooth | tail -30
|
||||||
|
ls -la ~/Downloads/ ~/Bluetooth/ 2>/dev/null
|
||||||
|
```
|
||||||
|
|
||||||
|
### Типичные ошибки
|
||||||
|
|
||||||
|
| Симптом | Действие |
|
||||||
|
|---------|----------|
|
||||||
|
| Нет диалога приёма на Fedora | Blueman → **Принять файл** **до** Send на Mac |
|
||||||
|
| «fedora не в Connected» на Mac | Fedora: BT on, Trust, не спать |
|
||||||
|
| Передача оборвалась | Файл < 50 MB надёжнее; повторить с шага 1 |
|
||||||
|
| Blueman нет в трее | `blueman-applet &` |
|
||||||
|
| obex не стартует | `sudo dnf install bluez-obexd blueman` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Альтернативы Bluetooth
|
||||||
|
|
||||||
|
Если BT-файлы не идут:
|
||||||
|
|
||||||
|
| Способ | Когда |
|
||||||
|
|--------|-------|
|
||||||
|
| **USB-флешка** | Самый надёжный offline |
|
||||||
|
| **USB tether** телефон → Fedora, `scp` с Mac в локалку | Если есть общая сеть |
|
||||||
|
| **Телефон как посредник** | Mac → телефон → Fedora (USB/BT) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. Порядок действий (шпаргалка)
|
||||||
|
|
||||||
|
```text
|
||||||
|
[FEDORA] Blueman → Принять файл → «Ожидание…»
|
||||||
|
[MAC] bash …/send-to-fedora-bluetooth.sh
|
||||||
|
[MAC] Bluetooth File Exchange → fedora → Send
|
||||||
|
[FEDORA] Файл в ~/Downloads
|
||||||
|
[FEDORA] tar xzf … && sudo bash install-….sh
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*docs/old_mac — local_machine*
|
||||||
88
docs/old_mac/README.md
Normal file
88
docs/old_mac/README.md
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
# Old Mac — Fedora 43 на MacBook Pro Intel
|
||||||
|
|
||||||
|
Контур для **старого MacBook Pro (Intel)** с Fedora 43: Wi‑Fi Broadcom BCM4322, offline firmware, передача файлов с основного Mac.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Документы
|
||||||
|
|
||||||
|
| Документ | Назначение |
|
||||||
|
|----------|------------|
|
||||||
|
| **[REMOTE_ACCESS.md](./REMOTE_ACCESS.md)** | **SSH и удалённое управление (хотспот / BT PAN)** |
|
||||||
|
| **[BLUETOOTH_FILE_TRANSFER.md](./BLUETOOTH_FILE_TRANSFER.md)** | Передача файлов Mac → Fedora по Bluetooth |
|
||||||
|
| [RUNBOOK.md](./RUNBOOK.md) | Wi‑Fi BCM4322: диагностика, firmware, PAN |
|
||||||
|
| [deliverable/fedora-bcm4322-wifi-fix.tar.gz](./deliverable/fedora-bcm4322-wifi-fix.tar.gz) | Архив для установки Wi‑Fi на Fedora |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Удалённое управление (SSH)
|
||||||
|
|
||||||
|
Оба на хотспоте телефона; прямой ping часто блокируется **изоляцией клиентов** → обход через **Bluetooth PAN**.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Mac (один раз)
|
||||||
|
bash ~/code/local_machine/docs/old_mac/scripts/setup-remote-mac.sh ВАШ_ЛОГИН_FEDORA
|
||||||
|
bash ~/code/local_machine/docs/old_mac/scripts/build-remote-access-archive.sh
|
||||||
|
bash ~/code/local_machine/docs/old_mac/scripts/send-to-fedora-bluetooth.sh \
|
||||||
|
~/code/local_machine/docs/old_mac/deliverable/fedora-remote-access.tar.gz
|
||||||
|
|
||||||
|
# Fedora (после приёма архива)
|
||||||
|
sudo bash setup-ssh-fedora.sh ВАШ_ЛОГИН
|
||||||
|
|
||||||
|
# Mac — подключение
|
||||||
|
bash ~/code/local_machine/docs/old_mac/scripts/connect-fedora.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Подробно: [REMOTE_ACCESS.md](./REMOTE_ACCESS.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Порядок:** сначала приём на Fedora, потом отправка с Mac.
|
||||||
|
|
||||||
|
1. **Fedora:** Blueman → **«Принять файл»** → «Ожидание входящего файла…»
|
||||||
|
2. **Mac:**
|
||||||
|
```bash
|
||||||
|
bash ~/code/local_machine/docs/old_mac/scripts/send-to-fedora-bluetooth.sh
|
||||||
|
```
|
||||||
|
3. **Mac:** Bluetooth File Exchange → **fedora** → **Send**
|
||||||
|
|
||||||
|
Подробно: [BLUETOOTH_FILE_TRANSFER.md](./BLUETOOTH_FILE_TRANSFER.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Wi‑Fi fix (после приёма архива)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/Downloads
|
||||||
|
tar xzf fedora-bcm4322-wifi-fix.tar.gz
|
||||||
|
cd fedora-bcm4322-wifi-fix
|
||||||
|
sudo bash install-bcm4322-firmware-fedora.sh
|
||||||
|
sudo reboot
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Скрипты (на этом Mac)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Отправить файл (по умолчанию — Wi-Fi архив)
|
||||||
|
bash ~/code/local_machine/docs/old_mac/scripts/send-to-fedora-bluetooth.sh
|
||||||
|
bash ~/code/local_machine/docs/old_mac/scripts/send-to-fedora-bluetooth.sh /path/to/anyfile.tar.gz
|
||||||
|
|
||||||
|
# Пересобрать delivery-архив
|
||||||
|
bash ~/code/local_machine/docs/old_mac/scripts/build-delivery-archive.sh
|
||||||
|
bash ~/code/local_machine/docs/old_mac/scripts/download-bcm4322-offline-bundle.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
На Fedora перед приёмом: `scripts/prepare-receive-fedora.sh` (подсказка; Blueman обязателен).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Железо
|
||||||
|
|
||||||
|
- **Fedora Mac:** MacBook Pro Intel, BCM4322, Fedora 43, ядро `6.17.1-300.fc43.x86_64`
|
||||||
|
- **BT-устройство:** fedora (`60:FB:42:7D:2D:66`)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*local_machine / docs/old_mac*
|
||||||
221
docs/old_mac/REMOTE_ACCESS.md
Normal file
221
docs/old_mac/REMOTE_ACCESS.md
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
# Удалённое управление Fedora MacBook с Mac (хотспот телефона)
|
||||||
|
|
||||||
|
**Схема:** оба ноутбука на Wi‑Fi хотспоте Redmi; прямой SSH часто **блокируется изоляцией клиентов** — обход через Bluetooth PAN.
|
||||||
|
|
||||||
|
**Проверено:** 2026-06-16 · `fedora.local` → `10.23.120.30`, ping с Mac **не проходит** (AP isolation).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Быстрый путь
|
||||||
|
|
||||||
|
### A. Один раз — Mac
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash ~/code/local_machine/docs/old_mac/scripts/setup-remote-mac.sh ВАШ_ЛОГИН_FEDORA
|
||||||
|
bash ~/code/local_machine/docs/old_mac/scripts/build-remote-access-archive.sh
|
||||||
|
bash ~/code/local_machine/docs/old_mac/scripts/send-to-fedora-bluetooth.sh \
|
||||||
|
~/code/local_machine/docs/old_mac/deliverable/fedora-remote-access.tar.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
### B. Один раз — Fedora (после приёма архива по BT)
|
||||||
|
|
||||||
|
Логин: **`p`**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/Downloads
|
||||||
|
tar xzf fedora-remote-access.tar.gz
|
||||||
|
cd fedora-remote-access
|
||||||
|
sudo bash setup-ssh-fedora.sh p
|
||||||
|
sudo bash setup-bt-pan-fedora.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### C. Подключение с Mac
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash ~/code/local_machine/docs/old_mac/scripts/bootstrap-ssh-fedora.sh # один раз, копирует ключ
|
||||||
|
bash ~/code/local_machine/docs/old_mac/scripts/connect-fedora.sh # дальше без пароля
|
||||||
|
```
|
||||||
|
|
||||||
|
Пароль хранится локально: `~/.config/old_mac/fedora.env` (см. `fedora.env.example`).
|
||||||
|
|
||||||
|
### D. RDP (графический стол, xrdp :3389)
|
||||||
|
|
||||||
|
На Fedora уже может быть xrdp. С Mac:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
brew install freerdp # один раз
|
||||||
|
bash ~/code/local_machine/docs/old_mac/scripts/connect-rdp-fedora.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Или **Microsoft Remote Desktop** (App Store): PC `fedora.local` или `10.23.120.30`, port **3389**, user **`p`**.
|
||||||
|
|
||||||
|
RDP и SSH одинаково **не достучатся**, пока нет L3 между Mac и Fedora (изоляция хотспота / нет BT PAN).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Диагностика сети хотспота
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash ~/code/local_machine/docs/old_mac/scripts/discover-fedora.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
| Результат | Значение |
|
||||||
|
|-----------|----------|
|
||||||
|
| `fedora.local` резолвится | Fedora в той же Wi‑Fi сети |
|
||||||
|
| `ping: ok` | Можно SSH по LAN (`ssh fedora-mbp`) |
|
||||||
|
| `ping: FAIL` + mDNS есть | **Изоляция клиентов** на телефоне → §4 BT PAN |
|
||||||
|
| `ssh:22 open` | `connect-fedora.sh` должен работать |
|
||||||
|
|
||||||
|
Текущая типичная картина:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Mac: 10.23.120.84/24
|
||||||
|
Gateway: 10.23.120.139 (телефон)
|
||||||
|
Fedora: 10.23.120.30 (fedora.local)
|
||||||
|
Ping Mac→Fedora: FAIL (изоляция)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Путь LAN (если ping проходит)
|
||||||
|
|
||||||
|
### 3.1 Отключить изоляцию на Redmi Note 14
|
||||||
|
|
||||||
|
Настройки → Режим модема / Точка доступа → **Дополнительно**:
|
||||||
|
|
||||||
|
- **AP isolation** / **Изоляция клиентов** → **Выкл**
|
||||||
|
- **Разрешить устройствам в сети видеть друг друга** → **Вкл** (если есть)
|
||||||
|
|
||||||
|
Переподключить Wi‑Fi на **обоих** Mac. Проверка:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ping -c2 fedora.local
|
||||||
|
bash ~/code/local_machine/docs/old_mac/scripts/connect-fedora.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2 SSH на Fedora
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo bash setup-ssh-fedora.sh USER
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.3 SSH с Mac
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh fedora-mbp # ~/.ssh/config
|
||||||
|
# или
|
||||||
|
bash connect-fedora.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Путь Bluetooth PAN (обход изоляции хотспота)
|
||||||
|
|
||||||
|
Прямой линк **Mac ↔ Fedora** поверх Bluetooth, минуя Wi‑Fi хотспота.
|
||||||
|
|
||||||
|
### 4.1 Fedora — PAN-сервер
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo bash setup-bt-pan-fedora.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Остаётся работать в фоне (`bt-network -s nap pan0`), IP Fedora: **172.20.99.1/24**.
|
||||||
|
|
||||||
|
### 4.2 Mac — подключить PAN
|
||||||
|
|
||||||
|
1. **Bluetooth** → устройство **fedora** → **Connect**
|
||||||
|
(профиль «Сеть» / Network Access Point / NAP — если спросит)
|
||||||
|
2. Настроить IP:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash ~/code/local_machine/docs/old_mac/scripts/setup-bt-pan-mac.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Mac получит **172.20.99.2/24**, ping Fedora:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ping -c2 172.20.99.1
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.3 SSH
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh fedora-mbp-bt
|
||||||
|
# или
|
||||||
|
bash ~/code/local_machine/docs/old_mac/scripts/connect-fedora.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Альтернатива: Internet Sharing (Mac → Fedora)
|
||||||
|
|
||||||
|
Если PAN с ручными IP капризничает:
|
||||||
|
|
||||||
|
1. **Mac:** Системные настройки → Общий доступ → **Общий интернет**
|
||||||
|
- Раздать от: **Wi‑Fi**
|
||||||
|
- Кому: **Bluetooth PAN**
|
||||||
|
2. **Fedora:** Bluetooth → подключиться к Mac как к сети
|
||||||
|
3. Fedora получит `192.168.2.x`, Mac обычно `192.168.2.1`
|
||||||
|
4. На Fedora узнать IP: `ip -4 addr show bnep0`
|
||||||
|
5. Добавить в Mac `~/.ssh/config` HostName с этим IP или `connect-fedora.sh`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Скрипты
|
||||||
|
|
||||||
|
| Скрипт | Где | Назначение |
|
||||||
|
|--------|-----|------------|
|
||||||
|
| `setup-remote-mac.sh` | Mac | SSH-ключ + `~/.ssh/config` |
|
||||||
|
| `build-remote-access-archive.sh` | Mac | Архив для Fedora |
|
||||||
|
| `send-to-fedora-bluetooth.sh` | Mac | Передать архив |
|
||||||
|
| `discover-fedora.sh` | Mac | Найти Fedora, проверить LAN |
|
||||||
|
| `connect-fedora.sh` | Mac | SSH (LAN или BT) |
|
||||||
|
| `setup-ssh-fedora.sh` | Fedora | sshd + authorized_keys |
|
||||||
|
| `setup-bt-pan-fedora.sh` | Fedora | BT PAN сервер |
|
||||||
|
| `setup-bt-pan-mac.sh` | Mac | IP на bnep0 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. SSH config (на Mac после setup-remote-mac)
|
||||||
|
|
||||||
|
```ssh-config
|
||||||
|
Host fedora-mbp old-mac-fedora fedora
|
||||||
|
User ВАШ_ЛОГИН
|
||||||
|
HostName fedora.local
|
||||||
|
IdentityFile ~/.ssh/id_ed25519_fedora
|
||||||
|
|
||||||
|
Host fedora-mbp-bt
|
||||||
|
HostName 172.20.99.1
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Устранение неполадок
|
||||||
|
|
||||||
|
| Проблема | Решение |
|
||||||
|
|----------|---------|
|
||||||
|
| Permission denied (publickey) | На Fedora: `setup-ssh-fedora.sh`, проверить `mac_pubkey.txt` |
|
||||||
|
| Connection refused :22 | `sudo systemctl start sshd` |
|
||||||
|
| No route to host (Wi‑Fi) | Изоляция хотспота → §4 BT PAN |
|
||||||
|
| Нет bnep0 на Mac | Fedora `setup-bt-pan-fedora.sh` + Bluetooth Connect |
|
||||||
|
| Fedora Wi‑Fi ещё без firmware | BT PAN или BT file transfer для архивов |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. Дерево решений
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
A[Нужен SSH на Fedora] --> B{ping fedora.local?}
|
||||||
|
B -->|ok| C[setup-ssh-fedora + ssh fedora-mbp]
|
||||||
|
B -->|fail| D[Изоляция хотспота]
|
||||||
|
D --> E{Можно выкл. AP isolation?}
|
||||||
|
E -->|да| C
|
||||||
|
E -->|нет| F[setup-bt-pan-fedora + setup-bt-pan-mac]
|
||||||
|
F --> G[ssh fedora-mbp-bt]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*docs/old_mac — local_machine*
|
||||||
116
docs/old_mac/RUNBOOK.md
Normal file
116
docs/old_mac/RUNBOOK.md
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
# Fedora 43 на MacBook Pro (Intel) — BCM4322 Wi‑Fi runbook
|
||||||
|
|
||||||
|
**Железо:** MacBook Pro Intel, Broadcom **BCM4322**, драйвер ядра **b43**
|
||||||
|
**ОС:** Fedora 43 Workstation, рабочее ядро `6.17.1-300.fc43.x86_64`
|
||||||
|
**Проверено:** 2026-06-16
|
||||||
|
|
||||||
|
**Архив для установки:** `deliverable/fedora-bcm4322-wifi-fix.tar.gz`
|
||||||
|
|
||||||
|
**Передача Mac → Fedora:** см. **[BLUETOOTH_FILE_TRANSFER.md](./BLUETOOTH_FILE_TRANSFER.md)** (порядок: приём на Fedora, затем Send с Mac).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Быстрый путь (Wi‑Fi fix)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/Downloads
|
||||||
|
tar xzf fedora-bcm4322-wifi-fix.tar.gz
|
||||||
|
cd fedora-bcm4322-wifi-fix
|
||||||
|
sudo bash install-bcm4322-firmware-fedora.sh
|
||||||
|
sudo reboot
|
||||||
|
nmcli device wifi list
|
||||||
|
nmcli device wifi connect "SSID" password "пароль"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. RCA
|
||||||
|
|
||||||
|
| Симптом | Причина | Решение |
|
||||||
|
|---------|---------|---------|
|
||||||
|
| `Broadcom 4322 WLAN found`, Wi‑Fi нет | Драйвер b43 есть, **firmware нет** | `ucode16_mimo.fw` в `/lib/firmware/b43/` |
|
||||||
|
| `b43-fwcutter` установлен | Это утилита, не firmware | Установить `.fw` файлы |
|
||||||
|
| BT PAN: `bnep0` connect → disconnect | Профиль NM / телефон | §4.2 |
|
||||||
|
| `dnf` timeout | Нет интернета | Offline-архив или USB tether |
|
||||||
|
|
||||||
|
**Не переустанавливать Fedora** — BCM4322 снова потребует firmware.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Диагностика
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uname -r
|
||||||
|
lspci -nn | grep -i network
|
||||||
|
lsmod | grep -E 'b43|bcma|ssb'
|
||||||
|
sudo dmesg | grep -i b43
|
||||||
|
nmcli device
|
||||||
|
ls -la /lib/firmware/b43/ucode16_mimo.fw
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Интернет до установки firmware
|
||||||
|
|
||||||
|
### USB tethering (предпочтительно)
|
||||||
|
|
||||||
|
Redmi Note 14 → USB-модем → на Fedora `nmcli device` → `ping 8.8.8.8`.
|
||||||
|
|
||||||
|
### Bluetooth PAN
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nmcli connection delete "Redmi Note 14 Network"
|
||||||
|
sudo systemctl restart bluetooth
|
||||||
|
bluetoothctl
|
||||||
|
# power on / agent on / default-agent / pair / trust / connect
|
||||||
|
```
|
||||||
|
|
||||||
|
На телефоне: Bluetooth-модем вкл., пересопрячь Fedora.
|
||||||
|
|
||||||
|
### Онлайн-путь (если интернет есть)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo dnf install rpmfusion-nonfree-release-tainted
|
||||||
|
sudo dnf install b43-firmware
|
||||||
|
sudo reboot
|
||||||
|
```
|
||||||
|
|
||||||
|
**Не ставить `akmod-wl`** на BCM4322.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. После установки
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo dmesg | grep -i b43 # нет "firmware ... not found"
|
||||||
|
nmcli device # wlan0 / wlp*
|
||||||
|
nmcli radio wifi on
|
||||||
|
nmcli device wifi list
|
||||||
|
```
|
||||||
|
|
||||||
|
Опционально (стабильность):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo iw dev <iface> set power_save off
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Ядро
|
||||||
|
|
||||||
|
Рабочее: **6.17.1-300.fc43.x86_64**. В GRUB не выбирать 7.0.12, если загрузка нестабильна.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Цель
|
||||||
|
|
||||||
|
| Компонент | Состояние |
|
||||||
|
|-----------|-----------|
|
||||||
|
| Firmware | `/lib/firmware/b43/ucode16_mimo.fw` |
|
||||||
|
| Драйвер | `b43` без ошибок в dmesg |
|
||||||
|
| Интерфейс | `wlan0` / `wlp*` в nmcli |
|
||||||
|
| Сеть | Wi‑Fi connect работает |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*docs/old_mac — local_machine*
|
||||||
7
docs/old_mac/bundle/bcm4322-offline-bundle/MANIFEST.txt
Normal file
7
docs/old_mac/bundle/bcm4322-offline-bundle/MANIFEST.txt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
BCM4322 b43 firmware offline bundle
|
||||||
|
Built: 2026-06-16
|
||||||
|
Source: broadcom-wl-6.30.163.46 via b43-fwcutter
|
||||||
|
Files: 155
|
||||||
|
Tarball: bcm4322-firmware-bundle.tar.gz
|
||||||
|
SHA256 tarball: 06d3f492c064c0db5549cf4e4bc5bd8fa40c15f3427ca02ec6a5d51f918b6032
|
||||||
|
SHA256 b43/ucode16_mimo.fw: 614c233b2f65653d298f74f64120068f84d031a40e3d37b68779ab7583fe574d
|
||||||
Binary file not shown.
Binary file not shown.
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/a0g0initvals5.fw
Normal file
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/a0g0initvals5.fw
Normal file
Binary file not shown.
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/a0g0initvals9.fw
Normal file
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/a0g0initvals9.fw
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/a0g1initvals13.fw
Normal file
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/a0g1initvals13.fw
Normal file
Binary file not shown.
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/a0g1initvals5.fw
Normal file
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/a0g1initvals5.fw
Normal file
Binary file not shown.
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/a0g1initvals9.fw
Normal file
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/a0g1initvals9.fw
Normal file
Binary file not shown.
Binary file not shown.
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/ac0initvals40.fw
Normal file
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/ac0initvals40.fw
Normal file
Binary file not shown.
Binary file not shown.
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/ac1initvals42.fw
Normal file
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/ac1initvals42.fw
Normal file
Binary file not shown.
Binary file not shown.
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/ac2initvals41.fw
Normal file
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/ac2initvals41.fw
Normal file
Binary file not shown.
Binary file not shown.
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/ac3initvals43.fw
Normal file
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/ac3initvals43.fw
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/b0g0initvals13.fw
Normal file
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/b0g0initvals13.fw
Normal file
Binary file not shown.
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/b0g0initvals5.fw
Normal file
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/b0g0initvals5.fw
Normal file
Binary file not shown.
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/b0g0initvals9.fw
Normal file
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/b0g0initvals9.fw
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/ht0initvals26.fw
Normal file
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/ht0initvals26.fw
Normal file
Binary file not shown.
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/ht0initvals29.fw
Normal file
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/ht0initvals29.fw
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/lcn0initvals24.fw
Normal file
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/lcn0initvals24.fw
Normal file
Binary file not shown.
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/lcn0initvals25.fw
Normal file
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/lcn0initvals25.fw
Normal file
Binary file not shown.
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/lcn0initvals26.fw
Normal file
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/lcn0initvals26.fw
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/lcn1initvals24.fw
Normal file
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/lcn1initvals24.fw
Normal file
Binary file not shown.
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/lcn1initvals25.fw
Normal file
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/lcn1initvals25.fw
Normal file
Binary file not shown.
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/lcn1initvals26.fw
Normal file
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/lcn1initvals26.fw
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/lcn2initvals24.fw
Normal file
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/lcn2initvals24.fw
Normal file
Binary file not shown.
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/lcn2initvals25.fw
Normal file
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/lcn2initvals25.fw
Normal file
Binary file not shown.
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/lcn2initvals26.fw
Normal file
BIN
docs/old_mac/bundle/bcm4322-offline-bundle/b43/lcn2initvals26.fw
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user