Skip to content
Ilia Maslakov edited this page Oct 17, 2026 · 1 revision

Сессии

M-Commander может пережить закрытие терминала или обрыв ssh, как программа под screen или tmux. Запущенный снова, он возвращает ту же сессию: панели, командную строку, открытые редакторы, копирование в фоне.

Это делает плагин session. Он выключен по умолчанию: кому сессии не нужны, у того ничего не меняется.

Как это устроено

Обычно, если закрыть вкладку терминала или если оборвётся ssh, mc получает SIGHUP и завершается вместе со всем, что было открыто. С включённым плагином mc никогда не работает прямо в терминале пользователя. Процессов три:

  • client сидит в терминале пользователя и передаёт ввод и вывод;
  • holder держит псевдотерминал mc и unix-сокет сессии, переживает закрытие терминала;
  • mc работает на псевдотерминале holder'а и не замечает, что терминал пользователя сменился.

Когда mc запускается в терминале, плагин ещё до инициализации экрана заменяет процесс на client (/usr/libexec/mcommander/session_helper). Client находит сессии по сокетам в $XDG_RUNTIME_DIR/mc6/sessions/, а если такого каталога нет, в $TMPDIR/mc6-sessions-UID/. Дальше он подключается к сессии или запускает новую. Поскольку у mc собственный псевдотерминал, после переподключения у программ, запущенных из mc, есть /dev/tty.

Вложенных сессий нет: mc, запущенный внутри сессии, свою сессию не заводит.

Ядро mc о сессиях не знает. Плагин пользуется общими сервисами, которые годятся и другим runtime-плагинам:

  • ранняя фаза до инициализации терминала;
  • слежение за дескриптором в главном цикле;
  • временная отдача терминала;
  • выход, как по F10, если ничего не открыто;
  • пункты меню;
  • флаг "выключен, пока не включат".

Новый терминал

При подключении нового терминала mc заново спрашивает у него возможности (цвета, клавиатура, графика) и полностью перерисовывает экран.

Новый терминал приносит с собой переменные SSH_AUTH_SOCK, SSH_AGENT_PID, DISPLAY, WAYLAND_DISPLAY, DBUS_SESSION_BUS_ADDRESS, XAUTHORITY, SSH_CONNECTION, SSH_CLIENT. Программы, которые mc запускает после этого, получают новые значения.

Оболочка командной строки запущена раньше и держит старое окружение, кроме агента. В сессии SSH_AUTH_SOCK указывает на ссылку <id>.agent рядом с сокетом, и holder при каждом подключении перенаправляет её на агента нового терминала. Поэтому git push из командной строки работает и после переподключения.

Включение

  1. Options, Manage plugins.
  2. Включить строку Sessions, сохранить.
  3. Выйти и запустить mc снова: плагин начинает работать со следующего запуска.

При сборке из исходников плагин собирается по умолчанию; ./configure --disable-session-plugin его выключает.

Запуск

Свободная сессия - это detached (в ней никого нет) или looks lost (её терминал 10 секунд не забирает вывод, как бывает за мёртвым ssh). Считаются только сессии с тем же TERM.

Сессии Что делает mc
свободных нет сразу запускает новую сессию
одна, detached сразу подключается к ней
две и больше, или есть looks lost показывает список, в нём видны и занятые
M-Commander sessions

  1  detached             /home/user/src
  2  attached, looks lost /home/user

  Enter  new session
  k N    end session N
  r      refresh
  q      shell

Number to take, Enter, k N, r or q:
  • N: взять сессию. Занятую другим терминалом mc берёт после вопроса y/N, looks lost забирает без вопроса.
  • Enter или n: новая сессия.
  • k N: закрыть mc в сессии N, как по F10. Если там открыт редактор, просмотрщик или диалог, mc отказывается. Если после этого свободных сессий не осталось, сразу запускается новая.
  • r: перечитать список.
  • q: вернуться в shell, сессии остаются.

Сессия не заводится:

  • на Linux console;
  • в mcedit6, mview и mdiff, запущенных отдельно;
  • в mc, запущенном внутри сессии;
  • когда stdin или stdout не терминал.

Диалог Sessions

Внутри сессии в меню Command (F9, Command) есть пункт Sessions.... Он открывает диалог со всеми сессиями; текущая показана как "this one", курсор стоит на первой другой.

  • Switch: перейти в выбранную сессию в этом терминале, текущая остаётся detached.
  • New: новая сессия в этом терминале, текущая остаётся detached.
  • End: закрыть выбранную сессию, как k. Текущую закрывают по F10.
  • Detach: вернуться в shell, сессия остаётся.

Терминал, у которого забрали сессию, возвращается в shell с сообщением [the session was taken by another terminal], режимы mc в нём (мышь, win32-input, kitty-клавиатура, альтернативный экран) выключены.

Автотест

В каталоге сборки (нужен python3):

make -C tests/misc check SUBDIRS= TESTS=session.py
cat tests/misc/session.py.log

17 шагов в псевдотерминалах:

  • плагин выключен по умолчанию;
  • сессия переживает закрытие терминала;
  • подключение без списка;
  • размер окна;
  • /dev/tty;
  • агент и DISPLAY;
  • Detach;
  • терминал, который не читает вывод;
  • looks lost;
  • сброс режимов у вытесненного терминала;
  • диалог: New, Switch, End, Detach;
  • k с открытым диалогом и без;
  • q.

Проверка руками

Выключен по умолчанию. Без включения в Manage plugins запустить mc, закрыть вкладку. Ожидается: mc завершается вместе с терминалом, в меню Command нет Sessions...

Закрытие вкладки. В mc открыть файл в редакторе (F4), закрыть вкладку терминала крестиком. Открыть новую вкладку, запустить mc. Ожидается: mc сразу возвращается с открытым редактором, без списка и без чёрного экрана.

Обрыв ssh. Зайти по ssh, запустить mc, оборвать соединение (убить ssh на своей стороне или отключить сеть). Зайти снова, запустить mc. Ожидается: если сервер уже заметил обрыв, сразу та же сессия. Если старая сессия ещё числится attached, запускается новая, а старую можно забрать через Sessions..., Switch (с вопросом). Если mc в старой сессии что-то выводил, она видна как looks lost, и в списке её забирают без вопроса.

Агент ssh. Зайти с ssh -A, запустить mc, отключиться, зайти снова с ssh -A, вернуться в сессию. В командной строке mc выполнить ssh-add -l или git fetch по ssh. Ожидается: агент нового подключения виден.

Две сессии и список. Сделать две detached-сессии (Sessions..., New, потом Sessions..., Detach). Запустить mc. Ожидается: список из двух сессий; номер берёт сессию; k 1 закрывает первую, и список остаётся со второй; второй k 1 закрывает последнюю, и сразу запускается новая.

Нельзя закрыть несохранённое. В сессии открыть редактор или диалог (F7), отсоединиться. Из другого терминала k N или End в диалоге. Ожидается: отказ с сообщением, сессия цела.

Забрать занятую сессию. mc в терминале A. В терминале B: Sessions..., Switch на сессию A, ответить Yes. Ожидается: сессия переходит в B; в A печатается сообщение, shell в A работает нормально, без мусора от клавиш. В Windows Terminal это заодно проверка, что режим win32-input выключен.

Разные размеры окна. Вернуться в сессию из окна другого размера. Ожидается: экран сразу перерисован под новый размер.

Фоновое копирование. Запустить большое копирование в фоне (F5, Background), закрыть терминал, через минуту вернуться. Ожидается: копирование шло всё это время.

Где сессии нет. Linux console, mcedit6 и mview, mc внутри сессии (из её командной строки), mc со stdin не из терминала. Ожидается: mc работает как без плагина.

Ограничения

  • В окне в 24 строки меню Command не помещается на экран, а меню mc не прокручиваются, так что Sessions... (последний пункт) не достать. Нужно окно от 25 строк.
  • Сессию looks lost mc при старте сам не забирает: её терминал может быть просто медленным.
  • Сессию с другим TERM взять нельзя.
  • Свежезапущенный mc около 1-2 секунд опрашивает терминал; клавиши, нажатые в это время, теряются.
  • Раздел о сессиях в man есть пока только на английском.

Откуда идея

Желание, чтобы mc переживал потерю терминала, пришло из PR #377 (unxed), который повторял "immortal" режим far2l. Устроено здесь иначе, по образцу screen и dtach; разница описана в PR ветки.

Clone this wiki locally