<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru"><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="http://russianpenguin.ru/feed.xml" rel="self" type="application/atom+xml" /><link href="http://russianpenguin.ru/" rel="alternate" type="text/html" hreflang="ru" /><updated>2026-02-10T23:30:26+03:00</updated><id>http://russianpenguin.ru/feed.xml</id><title type="html">Чтобы не забыть</title><subtitle>Записная книжка рассеянного [в пространстве и времени] программиста</subtitle><entry><title type="html">Windows: Как расшарить ключи между хостом и контейнерами wsl2</title><link href="http://russianpenguin.ru/2026/01/10/share-ssh-keys-with-wsl2-containers" rel="alternate" type="text/html" title="Windows: Как расшарить ключи между хостом и контейнерами wsl2" /><published>2026-01-10T00:00:00+03:00</published><updated>2026-01-10T00:00:00+03:00</updated><id>http://russianpenguin.ru/2026/01/10/share-ssh-keys-with-wsl2-containers</id><content type="html" xml:base="http://russianpenguin.ru/2026/01/10/share-ssh-keys-with-wsl2-containers"><![CDATA[<p>Самые простые способы копировать свои ключи в контейнер не буду описывать. Там просто копирование туда-сюда и смена прав доступа чтобы не ругался модуль.</p>

<h2 id="монтирование-папки-с-ключами">Монтирование папки с ключами</h2>

<p>Для этого добавляем запись в fstab с папкой. Она монтируется при помощи drvfs.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>C:\Users\&lt;your Windows username&gt;\.ssh\ /home/&lt;your Linux username&gt;/.ssh drvfs rw,noatime,uid=1000,gid=1000,case=off,umask=0077,fmask=0177 0 0
</code></pre></div></div>

<p>Запуск ssh-agent и добавление ключей осуществляется руками\systemctl\bashrc.</p>

<h2 id="использование-ssh-agent-из-хост-системы-в-контейнере">Использование ssh-agent из хост-системы в контейнере</h2>

<p>Для этого пользуемся <a href="https://github.com/mame/wsl2-ssh-agent">wsl2-ssh-agent</a>.</p>

<p>Автор описывает это как клиент-сервер, который перенаправляет запросы на ssh-agent из хост-системы.</p>

<ol>
  <li><code class="language-plaintext highlighter-rouge">mkdir -p ~/bin</code></li>
  <li>Загрузить</li>
</ol>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Для x86-64
curl -L -O https://github.com/mame/wsl2-ssh-agent/releases/latest/download/wsl2-ssh-agent
# Или для ARM64
curl -L -O https://github.com/mame/wsl2-ssh-agent/releases/latest/download/wsl2-ssh-agent-arm64
</code></pre></div></div>

<ol>
  <li>Добавить юнит для systemd <code class="language-plaintext highlighter-rouge">~/.config/systemd/user/wsl2-ssh-agent.service</code> (я предпочитаю править исходный конфиг потому что бинарник лежит в хомяке, а не в обшем <code class="language-plaintext highlighter-rouge">/bin</code>).</li>
</ol>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Unit]
Description=WSL2 SSH Agent Bridge
After=network.target
ConditionUser=!root

[Service]
ExecStart=%h/wsl2-ssh-agent --verbose --foreground --socket=%t/wsl2-ssh-agent.sock
Restart=on-failure

[Install]
WantedBy=default.target
</code></pre></div></div>

<ol>
  <li><code class="language-plaintext highlighter-rouge">systemctl --user enable --now wsl2-ssh-agent</code></li>
  <li>Добавить путь к сокету в .bashrc: <code class="language-plaintext highlighter-rouge">export SSH_AUTH_SOCK=$XDG_RUNTIME_DIR/wsl2-ssh-agent.sock</code></li>
  <li><code class="language-plaintext highlighter-rouge">source .bashrc</code></li>
  <li><code class="language-plaintext highlighter-rouge">ssh -T git@github.com</code></li>
</ol>]]></content><author><name></name></author><category term="HowTo" /><category term="windows" /><category term="git" /><category term="ssh" /><category term="wsl2" /><summary type="html"><![CDATA[Самые простые способы копировать свои ключи в контейнер не буду описывать. Там просто копирование туда-сюда и смена прав доступа чтобы не ругался модуль. Монтирование папки с ключами Для этого добавляем запись в fstab с папкой. Она монтируется при помощи drvfs. C:\Users\&lt;your Windows username&gt;\.ssh\ /home/&lt;your Linux username&gt;/.ssh drvfs rw,noatime,uid=1000,gid=1000,case=off,umask=0077,fmask=0177 0 0 Запуск ssh-agent и добавление ключей осуществляется руками\systemctl\bashrc. Использование ssh-agent из хост-системы в контейнере Для этого пользуемся wsl2-ssh-agent. Автор описывает это как клиент-сервер, который перенаправляет запросы на ssh-agent из хост-системы. mkdir -p ~/bin Загрузить # Для x86-64 curl -L -O https://github.com/mame/wsl2-ssh-agent/releases/latest/download/wsl2-ssh-agent # Или для ARM64 curl -L -O https://github.com/mame/wsl2-ssh-agent/releases/latest/download/wsl2-ssh-agent-arm64 Добавить юнит для systemd ~/.config/systemd/user/wsl2-ssh-agent.service (я предпочитаю править исходный конфиг потому что бинарник лежит в хомяке, а не в обшем /bin). [Unit] Description=WSL2 SSH Agent Bridge After=network.target ConditionUser=!root [Service] ExecStart=%h/wsl2-ssh-agent --verbose --foreground --socket=%t/wsl2-ssh-agent.sock Restart=on-failure [Install] WantedBy=default.target systemctl --user enable --now wsl2-ssh-agent Добавить путь к сокету в .bashrc: export SSH_AUTH_SOCK=$XDG_RUNTIME_DIR/wsl2-ssh-agent.sock source .bashrc ssh -T git@github.com]]></summary></entry><entry><title type="html">Windows: как подружить git и встроенный ssh</title><link href="http://russianpenguin.ru/2024/12/25/windows-git-ssh-agent" rel="alternate" type="text/html" title="Windows: как подружить git и встроенный ssh" /><published>2024-12-25T00:00:00+03:00</published><updated>2024-12-25T00:00:00+03:00</updated><id>http://russianpenguin.ru/2024/12/25/windows-ssh-agent-git</id><content type="html" xml:base="http://russianpenguin.ru/2024/12/25/windows-git-ssh-agent"><![CDATA[<p>Оказывается в винде уже достаточно долго можно ставить и использовать линуксовые сервисы без wsl из коробки. В том числе и ssh.</p>

<p>Конечно же хочется подружить имеющийся ssh с гитом и другими приложениями так, чтобы они автоматически использовали ssh-agent с хранилищем ключей.</p>

<p>Если этого не сделать, то гит в дефолтной конфигурации использует свой собсвенный ssh, а это приводит к тому, что каждый раз он запрашивает пароль для ключа.</p>

<h2 id="поставим-и-настроим-sshssh-agent">Поставим и настроим ssh+ssh-agent</h2>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Get-WindowsCapability <span class="nt">-Online</span> | ? Name <span class="nt">-like</span> <span class="s1">'OpenSSH.Client*'</span>
set-service ssh-agent <span class="nt">-StartupType</span> ‘Automatic’
Start-Service ssh-agent
</code></pre></div></div>

<p>Тем самым мы сделали два действия: поставили клиент и включили ssh-agent, а так же включили его запуск при старте системы.</p>

<h2 id="заставим-git-использовать-правильный-ssh">Заставим git использовать правильный ssh</h2>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git config <span class="nt">--global</span> core.sshCommand C:/Windows/System32/OpenSSH/ssh.exe
</code></pre></div></div>

<p>Указываем путь к ssh, который надо использовать.</p>

<p>Литература:</p>
<ul>
  <li><a href="https://learn.microsoft.com/ru-ru/windows-server/administration/openssh/openssh_install_firstuse?tabs=gui&amp;pivots=windows-server-2025">Начало работы с OpenSSH для Windows</a></li>
  <li><a href="https://petri.com/the-ultimate-guide-to-installing-openssh-on-windows/">The Ultimate Guide to Installing OpenSSH on Windows</a></li>
  <li><a href="https://interworks.com/blog/2021/09/15/setting-up-ssh-agent-in-windows-for-passwordless-git-authentication/">Configuring Git to Leverage the Windows SSH-Agent</a></li>
</ul>]]></content><author><name></name></author><category term="HowTo" /><category term="windows" /><category term="git" /><category term="ssh" /><summary type="html"><![CDATA[Оказывается в винде уже достаточно долго можно ставить и использовать линуксовые сервисы без wsl из коробки. В том числе и ssh. Конечно же хочется подружить имеющийся ssh с гитом и другими приложениями так, чтобы они автоматически использовали ssh-agent с хранилищем ключей. Если этого не сделать, то гит в дефолтной конфигурации использует свой собсвенный ssh, а это приводит к тому, что каждый раз он запрашивает пароль для ключа. Поставим и настроим ssh+ssh-agent Get-WindowsCapability -Online | ? Name -like 'OpenSSH.Client*' set-service ssh-agent -StartupType ‘Automatic’ Start-Service ssh-agent Тем самым мы сделали два действия: поставили клиент и включили ssh-agent, а так же включили его запуск при старте системы. Заставим git использовать правильный ssh git config --global core.sshCommand C:/Windows/System32/OpenSSH/ssh.exe Указываем путь к ssh, который надо использовать. Литература: Начало работы с OpenSSH для Windows The Ultimate Guide to Installing OpenSSH on Windows Configuring Git to Leverage the Windows SSH-Agent]]></summary></entry><entry><title type="html">Android: Настройка android emulator в windows</title><link href="http://russianpenguin.ru/2024/12/24/android-emulator-with-windows" rel="alternate" type="text/html" title="Android: Настройка android emulator в windows" /><published>2024-12-24T00:00:00+03:00</published><updated>2024-12-24T00:00:00+03:00</updated><id>http://russianpenguin.ru/2024/12/24/android-emulator-with-windows</id><content type="html" xml:base="http://russianpenguin.ru/2024/12/24/android-emulator-with-windows"><![CDATA[<p>Android Emulator, windows и встроенная видеокарта amd часто вызывают тонны головной боли.</p>

<ul>
  <li>не устанавливается aehd</li>
  <li>не запускается виртуальная машина</li>
</ul>

<p>Мы с вами рассмотрим обе эти проблемы и заодно поймём, почему большинство мануалов в интернете не работаю и не решают проблемы.</p>

<h2 id="не-работает-и-не-устанавливается-aehd">Не работает и не устанавливается aehd.</h2>

<p>Aehd (он же android emulator hypervisor driver) нужен для аппаратного ускорения виртуальных машинх. Если у вас есть поддержка виртуализации в процессоре (а она скорее всего у вас есть, ведь за последние годы просто перестали производить cpu без подобных расширений), то она вам точно нужна.</p>

<p>Сначала ставим android sdk, а потом видим, что не поставился android emulator driver.</p>

<p>Можно пойти по <a href="https://github.com/google/android-emulator-hypervisor-driver?tab=readme-ov-file">мануалу</a> и увидеть следующие ошибки в консоли:</p>

<pre><code class="language-commandline">&gt;silent_install.bat
[SC] ControlService FAILED 1062:

The service has not been started.

[SC] DeleteService SUCCESS
[SC] StartService FAILED with error 4294967201
</code></pre>

<p>Если кратко, то существуют два способа запуска эмулятора на винде.</p>
<ol>
  <li>Aehd. Он же android emulator hypervisor driver. Является форком kvm под винду</li>
  <li>Hyper V. Он же компонент винды и платформа для виртуализации уже в маздае.</li>
</ol>

<p>Чем же они принципиально отличаются и нужен ли вам первый или второй?</p>

<p>Первый нужен для всех версий ниже pro. Потому что в них нет гипер ви. А вот всё, что выше pro должно работать уже с нормальным гипервизором.</p>

<p>Поэтому если у вас первый вариант (а скорее всего у вас win &gt;= pro :)), то смотрим в документацию.</p>

<p>А вот если у вас второй вариант, то надо обязательно поставить платформу hyper v из дополнительных компонентов windowa в панели управления.</p>

<p>Картинки <a href="https://android-developers.googleblog.com/2018/07/android-emulator-amd-processor-hyper-v.html">тут</a>.</p>

<h2 id="не-запускается-эмулятор">Не запускается эмулятор</h2>

<p>А вот тут у вас скорее всего AMD и комбинация из встроенной и дискретной видеокарты.</p>

<p>Что можно сделать?</p>

<p>Идём в папку sdk с эмулятором.</p>

<pre><code class="language-commandline">&gt;cd %USERPROFILE%\AppData\Local\Android\Sdk\emulator
</code></pre>

<p>Смотрим, какие машинки созданы в андроид-студии.</p>

<pre><code class="language-commandline">&gt;emulator -list-avds
Medium_Phone_API_35
</code></pre>

<p>У меня это только <code class="language-plaintext highlighter-rouge">Medium_Phone_API_35</code>.</p>

<p>Пробуем её запустить и мониторим консоль на предмет ошибок. Скорее всего у вас тоже будет что-то такое как у меня.</p>

<pre><code class="language-commandline">&gt;emulator -avd Medium_Phone_API_35 -netdelay none -netspeed full -qt-hide-window -grpc-use-token -idle-grpc-timeout 0

...

←[0;39mandroid_startOpenglesRenderer: gpu infoGPU #1
  Make: 10de
  Model: NVIDIA GeForce GTX 1650 Ti
  Device ID: 1f95
I1224 02:58:38.110433    2788 HealthMonitor.cpp:279] HealthMonitor disabled.
I1224 02:58:38.110789    2788 VulkanDispatch.cpp:137] Added library: vulkan-1.dll
ERROR:             vkGetPhysicalDeviceProperties: Invalid physicalDevice [VUID-vkGetPhysicalDeviceProperties-physicalDevice-parameter]
</code></pre>

<p>И если мы видим что-то связанное с вулканом, то сначала пробуем отключить его через консоль. Добавляем параметр <code class="language-plaintext highlighter-rouge">-feature -Vulkan</code>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt;emulator -avd Medium_Phone_API_35 -netdelay none -netspeed full -qt-hide-window -grpc-use-token -idle-grpc-timeout 0 -feature -Vulkan
</code></pre></div></div>

<p>Эмулятор запустился скорее всего. Завершаем его по <code class="language-plaintext highlighter-rouge">ctrl-c</code>. И теперь надо сконфигурировать студию так, чтобы в эмуляторах она вулкан не использовала.</p>

<p>Не надо отключать автоматический выбор видеокарты как это делаю многие через задание перемённой <code class="language-plaintext highlighter-rouge">DISABLE_LAYER_AMD_SWITCHABLE_GRAPHICS_1</code>. Очень опрометчивое решение. Не рекомендую.</p>

<p>Редактируем файл <code class="language-plaintext highlighter-rouge">%USERPROFILE%\.android\advancedFeatures.ini</code> добавляя в него пару строк для отключения. Если файла нет, то надо его создать.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Vulkan = off
GLDirectMem = on
</code></pre></div></div>

<p>И, кстати, этот приём действует как для маздая, так и для линукса. Они оба подвержены проблеме с графиков.</p>

<p>Решится это может только обновлением драйвера для amd, что маловероятно.</p>

<p>Документация в которой ничего нет:</p>
<ul>
  <li>https://developer.android.com/studio/run/emulator-troubleshooting?hl=ru</li>
</ul>]]></content><author><name></name></author><category term="HowTo" /><category term="windows" /><category term="android" /><category term="virtualization" /><category term="bug" /><summary type="html"><![CDATA[Android Emulator, windows и встроенная видеокарта amd часто вызывают тонны головной боли. не устанавливается aehd не запускается виртуальная машина Мы с вами рассмотрим обе эти проблемы и заодно поймём, почему большинство мануалов в интернете не работаю и не решают проблемы. Не работает и не устанавливается aehd. Aehd (он же android emulator hypervisor driver) нужен для аппаратного ускорения виртуальных машинх. Если у вас есть поддержка виртуализации в процессоре (а она скорее всего у вас есть, ведь за последние годы просто перестали производить cpu без подобных расширений), то она вам точно нужна. Сначала ставим android sdk, а потом видим, что не поставился android emulator driver. Можно пойти по мануалу и увидеть следующие ошибки в консоли: &gt;silent_install.bat [SC] ControlService FAILED 1062: The service has not been started. [SC] DeleteService SUCCESS [SC] StartService FAILED with error 4294967201 Если кратко, то существуют два способа запуска эмулятора на винде. Aehd. Он же android emulator hypervisor driver. Является форком kvm под винду Hyper V. Он же компонент винды и платформа для виртуализации уже в маздае. Чем же они принципиально отличаются и нужен ли вам первый или второй? Первый нужен для всех версий ниже pro. Потому что в них нет гипер ви. А вот всё, что выше pro должно работать уже с нормальным гипервизором. Поэтому если у вас первый вариант (а скорее всего у вас win &gt;= pro :)), то смотрим в документацию. А вот если у вас второй вариант, то надо обязательно поставить платформу hyper v из дополнительных компонентов windowa в панели управления. Картинки тут. Не запускается эмулятор А вот тут у вас скорее всего AMD и комбинация из встроенной и дискретной видеокарты. Что можно сделать? Идём в папку sdk с эмулятором. &gt;cd %USERPROFILE%\AppData\Local\Android\Sdk\emulator Смотрим, какие машинки созданы в андроид-студии. &gt;emulator -list-avds Medium_Phone_API_35 У меня это только Medium_Phone_API_35. Пробуем её запустить и мониторим консоль на предмет ошибок. Скорее всего у вас тоже будет что-то такое как у меня. &gt;emulator -avd Medium_Phone_API_35 -netdelay none -netspeed full -qt-hide-window -grpc-use-token -idle-grpc-timeout 0 ... ←[0;39mandroid_startOpenglesRenderer: gpu infoGPU #1 Make: 10de Model: NVIDIA GeForce GTX 1650 Ti Device ID: 1f95 I1224 02:58:38.110433 2788 HealthMonitor.cpp:279] HealthMonitor disabled. I1224 02:58:38.110789 2788 VulkanDispatch.cpp:137] Added library: vulkan-1.dll ERROR: vkGetPhysicalDeviceProperties: Invalid physicalDevice [VUID-vkGetPhysicalDeviceProperties-physicalDevice-parameter] И если мы видим что-то связанное с вулканом, то сначала пробуем отключить его через консоль. Добавляем параметр -feature -Vulkan. &gt;emulator -avd Medium_Phone_API_35 -netdelay none -netspeed full -qt-hide-window -grpc-use-token -idle-grpc-timeout 0 -feature -Vulkan Эмулятор запустился скорее всего. Завершаем его по ctrl-c. И теперь надо сконфигурировать студию так, чтобы в эмуляторах она вулкан не использовала. Не надо отключать автоматический выбор видеокарты как это делаю многие через задание перемённой DISABLE_LAYER_AMD_SWITCHABLE_GRAPHICS_1. Очень опрометчивое решение. Не рекомендую. Редактируем файл %USERPROFILE%\.android\advancedFeatures.ini добавляя в него пару строк для отключения. Если файла нет, то надо его создать. Vulkan = off GLDirectMem = on И, кстати, этот приём действует как для маздая, так и для линукса. Они оба подвержены проблеме с графиков. Решится это может только обновлением драйвера для amd, что маловероятно. Документация в которой ничего нет: https://developer.android.com/studio/run/emulator-troubleshooting?hl=ru]]></summary></entry><entry><title type="html">KDE: Dolphin не может создать файл на nfs, а консоль может</title><link href="http://russianpenguin.ru/2024/10/21/dolphin-nfs-bug" rel="alternate" type="text/html" title="KDE: Dolphin не может создать файл на nfs, а консоль может" /><published>2024-10-22T00:00:00+03:00</published><updated>2024-10-22T00:00:00+03:00</updated><id>http://russianpenguin.ru/2024/10/21/dolphin-nfs-bug</id><content type="html" xml:base="http://russianpenguin.ru/2024/10/21/dolphin-nfs-bug"><![CDATA[<p>Итак. Существует проблема в связке nfs+dolphin. Настолько большая, что многие пользователи попросту не используют nfs.</p>

<p>Она заключается в том, что если на каталоге установлено сопоставление с анонимным пользователем для всех (через <code class="language-plaintext highlighter-rouge">all_squash</code>), то в ряде случаев пользователи просто не могут создавать каталоги и файлы из dolphin (где-то видел упоминание о том, что nautilus так же поломан). Только через консоль (либо альтернативные менеджеры)</p>

<p>Проблема имеет лишь несколько веток на реддите вида <a href="https://www.reddit.com/r/kde/comments/n55jp9/dolphin_cant_edit_synology_nfs_folders_even_when/">Dolphin Can’t Edit Synology NFS Folders Even When User Has Permissions?</a></p>

<p>Хотя и обычный nfs подвержен таким же проблемам.</p>

<p>Рассматривать будем на примере nas от synology.</p>

<p>Данное явление распространяется как на nfs3, так и на nfs4. Последнюю использовать дома смысла нет - её преимущества раскрываются только в домене.</p>

<p>На записи ниже хорошо видно как проявляет себя проблема.</p>

<video width="100%" controls="" preload="metadata">
  <source src="/assets/images/2024/dolphin_nfs_bug/6a89f6427a95b3150c86e822a8d5521d_MD5.webm" type="video/webm" />
</video>

<p>Казалось бы. Пользователь сопоставляется с админом. На каталоге есть права для пользователя. Что ещё надо?</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># cat /etc/exports  </span>
/volume1/projects  192.168.1.0/24<span class="o">(</span>rw,async,no_wdelay,all_squash,insecure_locks,sec<span class="o">=</span>sys,anonuid<span class="o">=</span>1024,anongid<span class="o">=</span>100<span class="o">)</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">ls</span> <span class="nt">-ld</span> misc/  
drwxrwxr-x. 3 nas-writer <span class="nb">users </span>4096 окт 21 23:14 misc/  
<span class="nv">$ </span><span class="nb">ls</span> <span class="nt">-ld</span> misc/Новая<span class="se">\ </span>папка/  
drwxr-xr-x. 2 nas-writer <span class="nb">users </span>4096 окт 21 23:18 <span class="s1">'misc/Новая папка/'</span>  
</code></pre></div></div>

<p>Попробуем добавить прав как это сделано с родительским каталогом.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">sudo chmod </span>g+w misc/Новая<span class="se">\ </span>папка/
<span class="nv">$ </span><span class="nb">ls</span> <span class="nt">-ld</span> misc/Новая<span class="se">\ </span>папка/  
drwxrwxr-x. 2 nas-writer <span class="nb">users </span>4096 окт 21 23:18 <span class="s1">'misc/Новая папка/'</span>
</code></pre></div></div>

<p>И опять ничего не выходит:</p>

<p><img src="/assets/images/2024/dolphin_nfs_bug/9ef60aee72f95a00b4d0572c324f03f4_MD5.jpeg" alt="Ничего не получилось" /></p>

<p>И даже если добавить права на всех (<code class="language-plaintext highlighter-rouge">a+w</code>), то мы тоже не сможем создавать файлы и каталоги из файлового менеджера.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">sudo chmod </span>a+w misc/Новая<span class="se">\ </span>папка/  
<span class="nv">$ </span><span class="nb">ls</span> <span class="nt">-ld</span> misc/Новая<span class="se">\ </span>папка/  
drwxrwxrwx. 2 nas-writer <span class="nb">users </span>4096 окт 21 23:18 <span class="s1">'misc/Новая папка/'</span>
</code></pre></div></div>

<p>Корни проблемы:</p>
<ul>
  <li>в первую очередь проблема в KIO и KDE (там есть баг аж от 2015 года).</li>
  <li>во вторую очередь - это чехарда с правами на самой станции (которая иногда случается когда файлы копируются туда-сюда или рсинкаются).</li>
</ul>

<p>Давайте посмотрим на то, что происходит на станции.</p>

<p>Разрешения папки misc.</p>

<p><img src="/assets/images/2024/dolphin_nfs_bug/3b4174822f49599395ff1c4eaeda13f1_MD5.jpeg" alt="Разрешения папки misc" /></p>

<p>И разрешение папки <code class="language-plaintext highlighter-rouge">Новая папка</code>.</p>

<p><img src="/assets/images/2024/dolphin_nfs_bug/167ea6afd0aa0b3483849767bccba834_MD5.jpeg" alt="Разрешения новой папки" /></p>

<p>Очевидно, что они наследуются. Разрешение на запись для админа выглядит так:</p>

<p><img src="/assets/images/2024/dolphin_nfs_bug/bab914c1278a76acf958f859b71744a9_MD5.jpeg" alt="Админские права" /></p>

<p>Однако, если мы поставим <code class="language-plaintext highlighter-rouge">a+w</code> на папку misc, то dolphin сможет создавать файлы внутри нового каталога. И мы можем даже убрать права <code class="language-plaintext highlighter-rouge">o-w</code> на новую папку! И всё равно файлы создавать можно.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">sudo chmod </span>a+w misc  
<span class="nv">$ </span><span class="nb">ls</span> <span class="nt">-ld</span> misc/  
drwxrwxrwx. 4 nas-writer <span class="nb">users </span>4096 окт 21 23:18 misc/  
<span class="nv">$ </span><span class="nb">sudo chmod </span>o-w misc/Новая<span class="se">\ </span>папка/  
<span class="nv">$ </span><span class="nb">ls</span> <span class="nt">-ld</span> misc/Новая<span class="se">\ </span>папка/  
drwxrwxr-x. 2 nas-writer <span class="nb">users </span>4096 окт 21 23:18 <span class="s1">'misc/Новая папка/'</span>
</code></pre></div></div>

<p><img src="/assets/images/2024/dolphin_nfs_bug/4e8b8b8d77aaa524b593353a2961e26d_MD5.jpeg" alt="Пробуем починить" /></p>

<p>И я даже знать не хочу почему это работает.</p>

<p>Теперь мы можем всё починить. Так как при создании папок права наследуются от родительского объекта, то нам нужно для группы администраторов (а в данном случае это именно так и есть) дать полный доступ на родительский каталог и на все существующие в данным момент папки.</p>

<p>Для этого установим администраторов единственной группой с полным доступом к файлам.</p>

<p>Для этого в файловом менеджере на станции выбираем экспортируемый каталог и на вкладке разрешений устанавливаем следующие права.</p>

<p>Обязательно выставляем флажок для применения ко вложенным объектам.</p>

<p><img src="/assets/images/2024/dolphin_nfs_bug/e145101c2fc3154aa78d225d00cc1842_MD5.jpeg" alt="Чиним нормально" /></p>

<p>Стоит отметить еще один эффект: теперь все файлы и папки создаются с правами 777.</p>

<video width="100%" controls="" preload="metadata">
  <source src="/assets/images/2024/dolphin_nfs_bug/90442a9b1f85f16c8f94794f4a35abea_MD5.webm" type="video/webm" />
</video>

<p>Даже если они создаются через smb-шару.</p>

<p>Речь идет только о шарах с полным доступом для всех пользователей. Т.н. файлопомойки. Задача таких мест - это позволять любому пользователю писать и удалять любые объекты. В статье мы не рассматриваем случай с авторизованными пользователями - там всё и так хорошо.</p>

<p>Вообще стоит объяснить почему так происходит.</p>

<p>В данном случае применяется не обычные права доступа, а расширенный acl. Он настраивается таким образом, что дочерние объекты наследуют пермиссии родительских.</p>

<p>Давайте посмотрим на примере.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">mkdir test</span>  
<span class="nv">$ </span><span class="nb">ls</span> <span class="nt">-la</span>  
итого 0  
drwxr-xr-x. 1 penguin penguin   8 окт 22 00:11 <span class="nb">.</span>  
drwx------. 1 penguin penguin 810 окт 22 00:05 ..  
drwxr-xr-x. 1 penguin penguin   0 окт 22 00:11 <span class="nb">test</span>  
<span class="nv">$ </span><span class="nb">cd test</span>/  
<span class="nv">$ </span><span class="nb">mkdir </span>test_2  
<span class="nv">$ </span><span class="nb">ls</span> <span class="nt">-la</span>  
итого 0  
drwxr-xr-x. 1 penguin penguin 12 окт 22 00:11 <span class="nb">.</span>  
drwxr-xr-x. 1 penguin penguin  8 окт 22 00:11 ..  
drwxr-xr-x. 1 penguin penguin  0 окт 22 00:11 test_2  
<span class="nv">$ </span><span class="nb">cd</span> ..  
<span class="nv">$ </span><span class="nb">chmod </span>g+w <span class="nb">test</span>/  
<span class="nv">$ </span><span class="nb">cd test</span>/  
<span class="nv">$ </span><span class="nb">mkdir </span>test_3  
<span class="nv">$ </span><span class="nb">ls</span> <span class="nt">-la</span>  
итого 0  
drwxrwxr-x. 1 penguin penguin 24 окт 22 00:11 <span class="nb">.</span>  
drwxr-xr-x. 1 penguin penguin  8 окт 22 00:11 ..  
drwxr-xr-x. 1 penguin penguin  0 окт 22 00:11 test_2  
drwxr-xr-x. 1 penguin penguin  0 окт 22 00:11 test_3
</code></pre></div></div>

<p>Видим, что изменение прав на родительский каталог никак не повлияло на создание дочернего каталога <code class="language-plaintext highlighter-rouge">test_3</code>. Потому что права подчиняются установленной в система <code class="language-plaintext highlighter-rouge">umask</code>, <code class="language-plaintext highlighter-rouge">dmask</code> и <code class="language-plaintext highlighter-rouge">fmask</code>.</p>

<p>А теперь то же самое, но с acl.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">mkdir test</span>  
<span class="nv">$ </span><span class="nb">ls</span> <span class="nt">-la</span>  
итого 0  
drwxr-xr-x. 1 penguin penguin   8 окт 22 00:16 <span class="nb">.</span>  
drwx------. 1 penguin penguin 810 окт 22 00:05 ..  
drwxr-xr-x. 1 penguin penguin   0 окт 22 00:16 <span class="nb">test</span>  
<span class="nv">$ </span><span class="nb">cd test</span>/  
<span class="nv">$ </span><span class="nb">mkdir </span>test_2  
<span class="nv">$ </span><span class="nb">ls</span> <span class="nt">-la</span>  
итого 0  
drwxr-xr-x. 1 penguin penguin 12 окт 22 00:16 <span class="nb">.</span>  
drwxr-xr-x. 1 penguin penguin  8 окт 22 00:16 ..  
drwxr-xr-x. 1 penguin penguin  0 окт 22 00:16 test_2  
<span class="nv">$ </span><span class="nb">cd</span> ../  
<span class="nv">$ </span>setfacl <span class="nt">--recursive</span> <span class="nt">--modify</span> u:penguin:rwX,g:penguin:rwX,d:g:penguin:rwX,d:u:penguin:rwX <span class="nb">test</span>  
<span class="nv">$ </span><span class="nb">ls</span> <span class="nt">-la</span>  
итого 0  
drwxr-xr-x. 1 penguin penguin   8 окт 22 00:16 <span class="nb">.</span>  
drwx------. 1 penguin penguin 810 окт 22 00:05 ..  
drwxrwxr-x+ 1 penguin penguin  12 окт 22 00:16 <span class="nb">test</span>  
<span class="nv">$ </span>getfacl <span class="nb">test</span>/  
<span class="c"># file: test/  </span>
<span class="c"># owner: penguin  </span>
<span class="c"># group: penguin  </span>
user::rwx  
user:penguin:rwx  
group::r-x  
group:penguin:rwx  
mask::rwx  
other::r-x  
default:user::rwx  
default:user:penguin:rwx  
default:group::r-x  
default:group:penguin:rwx  
default:mask::rwx  
default:other::r-x  
  
<span class="nv">$ </span><span class="nb">cd test</span>/  
<span class="nv">$ </span><span class="nb">ls</span> <span class="nt">-la</span>  
итого 0  
drwxrwxr-x+ 1 penguin penguin 12 окт 22 00:16 <span class="nb">.</span>  
drwxr-xr-x. 1 penguin penguin  8 окт 22 00:16 ..  
drwxrwxr-x+ 1 penguin penguin  0 окт 22 00:16 test_2  
<span class="nv">$ </span><span class="nb">mkdir </span>test_3  
<span class="nv">$ </span><span class="nb">ls</span> <span class="nt">-la</span>  
итого 0  
drwxrwxr-x+ 1 penguin penguin 24 окт 22 00:18 <span class="nb">.</span>  
drwxr-xr-x. 1 penguin penguin  8 окт 22 00:16 ..  
drwxrwxr-x+ 1 penguin penguin  0 окт 22 00:16 test_2  
drwxrwxr-x+ 1 penguin penguin  0 окт 22 00:18 test_3
</code></pre></div></div>

<p>В этом и кроется способ починки nfs и dolphin.</p>

<p>И еще стоит обратить внимание, что acl для nfs4 отличается. И именно поэтому стоит использовать nfs3 если у вас нет домена.</p>]]></content><author><name></name></author><category term="HowTo" /><category term="Баги" /><category term="kde" /><category term="console" /><category term="network" /><category term="linux" /><summary type="html"><![CDATA[Итак. Существует проблема в связке nfs+dolphin. Настолько большая, что многие пользователи попросту не используют nfs. Она заключается в том, что если на каталоге установлено сопоставление с анонимным пользователем для всех (через all_squash), то в ряде случаев пользователи просто не могут создавать каталоги и файлы из dolphin (где-то видел упоминание о том, что nautilus так же поломан). Только через консоль (либо альтернативные менеджеры) Проблема имеет лишь несколько веток на реддите вида Dolphin Can’t Edit Synology NFS Folders Even When User Has Permissions? Хотя и обычный nfs подвержен таким же проблемам. Рассматривать будем на примере nas от synology. Данное явление распространяется как на nfs3, так и на nfs4. Последнюю использовать дома смысла нет - её преимущества раскрываются только в домене. На записи ниже хорошо видно как проявляет себя проблема. Казалось бы. Пользователь сопоставляется с админом. На каталоге есть права для пользователя. Что ещё надо? # cat /etc/exports /volume1/projects 192.168.1.0/24(rw,async,no_wdelay,all_squash,insecure_locks,sec=sys,anonuid=1024,anongid=100) $ ls -ld misc/ drwxrwxr-x. 3 nas-writer users 4096 окт 21 23:14 misc/ $ ls -ld misc/Новая\ папка/ drwxr-xr-x. 2 nas-writer users 4096 окт 21 23:18 'misc/Новая папка/' Попробуем добавить прав как это сделано с родительским каталогом. $ sudo chmod g+w misc/Новая\ папка/ $ ls -ld misc/Новая\ папка/ drwxrwxr-x. 2 nas-writer users 4096 окт 21 23:18 'misc/Новая папка/' И опять ничего не выходит: И даже если добавить права на всех (a+w), то мы тоже не сможем создавать файлы и каталоги из файлового менеджера. $ sudo chmod a+w misc/Новая\ папка/ $ ls -ld misc/Новая\ папка/ drwxrwxrwx. 2 nas-writer users 4096 окт 21 23:18 'misc/Новая папка/' Корни проблемы: в первую очередь проблема в KIO и KDE (там есть баг аж от 2015 года). во вторую очередь - это чехарда с правами на самой станции (которая иногда случается когда файлы копируются туда-сюда или рсинкаются). Давайте посмотрим на то, что происходит на станции. Разрешения папки misc. И разрешение папки Новая папка. Очевидно, что они наследуются. Разрешение на запись для админа выглядит так: Однако, если мы поставим a+w на папку misc, то dolphin сможет создавать файлы внутри нового каталога. И мы можем даже убрать права o-w на новую папку! И всё равно файлы создавать можно. $ sudo chmod a+w misc $ ls -ld misc/ drwxrwxrwx. 4 nas-writer users 4096 окт 21 23:18 misc/ $ sudo chmod o-w misc/Новая\ папка/ $ ls -ld misc/Новая\ папка/ drwxrwxr-x. 2 nas-writer users 4096 окт 21 23:18 'misc/Новая папка/' И я даже знать не хочу почему это работает. Теперь мы можем всё починить. Так как при создании папок права наследуются от родительского объекта, то нам нужно для группы администраторов (а в данном случае это именно так и есть) дать полный доступ на родительский каталог и на все существующие в данным момент папки. Для этого установим администраторов единственной группой с полным доступом к файлам. Для этого в файловом менеджере на станции выбираем экспортируемый каталог и на вкладке разрешений устанавливаем следующие права. Обязательно выставляем флажок для применения ко вложенным объектам. Стоит отметить еще один эффект: теперь все файлы и папки создаются с правами 777. Даже если они создаются через smb-шару. Речь идет только о шарах с полным доступом для всех пользователей. Т.н. файлопомойки. Задача таких мест - это позволять любому пользователю писать и удалять любые объекты. В статье мы не рассматриваем случай с авторизованными пользователями - там всё и так хорошо. Вообще стоит объяснить почему так происходит. В данном случае применяется не обычные права доступа, а расширенный acl. Он настраивается таким образом, что дочерние объекты наследуют пермиссии родительских. Давайте посмотрим на примере. $ mkdir test $ ls -la итого 0 drwxr-xr-x. 1 penguin penguin   8 окт 22 00:11 . drwx------. 1 penguin penguin 810 окт 22 00:05 .. drwxr-xr-x. 1 penguin penguin   0 окт 22 00:11 test $ cd test/ $ mkdir test_2 $ ls -la итого 0 drwxr-xr-x. 1 penguin penguin 12 окт 22 00:11 . drwxr-xr-x. 1 penguin penguin  8 окт 22 00:11 .. drwxr-xr-x. 1 penguin penguin  0 окт 22 00:11 test_2 $ cd .. $ chmod g+w test/ $ cd test/ $ mkdir test_3 $ ls -la итого 0 drwxrwxr-x. 1 penguin penguin 24 окт 22 00:11 . drwxr-xr-x. 1 penguin penguin  8 окт 22 00:11 .. drwxr-xr-x. 1 penguin penguin  0 окт 22 00:11 test_2 drwxr-xr-x. 1 penguin penguin  0 окт 22 00:11 test_3 Видим, что изменение прав на родительский каталог никак не повлияло на создание дочернего каталога test_3. Потому что права подчиняются установленной в система umask, dmask и fmask. А теперь то же самое, но с acl. $ mkdir test $ ls -la итого 0 drwxr-xr-x. 1 penguin penguin   8 окт 22 00:16 . drwx------. 1 penguin penguin 810 окт 22 00:05 .. drwxr-xr-x. 1 penguin penguin   0 окт 22 00:16 test $ cd test/ $ mkdir test_2 $ ls -la итого 0 drwxr-xr-x. 1 penguin penguin 12 окт 22 00:16 . drwxr-xr-x. 1 penguin penguin  8 окт 22 00:16 .. drwxr-xr-x. 1 penguin penguin  0 окт 22 00:16 test_2 $ cd ../ $ setfacl --recursive --modify u:penguin:rwX,g:penguin:rwX,d:g:penguin:rwX,d:u:penguin:rwX test $ ls -la итого 0 drwxr-xr-x. 1 penguin penguin   8 окт 22 00:16 . drwx------. 1 penguin penguin 810 окт 22 00:05 .. drwxrwxr-x+ 1 penguin penguin  12 окт 22 00:16 test $ getfacl test/ # file: test/ # owner: penguin # group: penguin user::rwx user:penguin:rwx group::r-x group:penguin:rwx mask::rwx other::r-x default:user::rwx default:user:penguin:rwx default:group::r-x default:group:penguin:rwx default:mask::rwx default:other::r-x $ cd test/ $ ls -la итого 0 drwxrwxr-x+ 1 penguin penguin 12 окт 22 00:16 . drwxr-xr-x. 1 penguin penguin  8 окт 22 00:16 .. drwxrwxr-x+ 1 penguin penguin  0 окт 22 00:16 test_2 $ mkdir test_3 $ ls -la итого 0 drwxrwxr-x+ 1 penguin penguin 24 окт 22 00:18 . drwxr-xr-x. 1 penguin penguin  8 окт 22 00:16 .. drwxrwxr-x+ 1 penguin penguin  0 окт 22 00:16 test_2 drwxrwxr-x+ 1 penguin penguin  0 окт 22 00:18 test_3 В этом и кроется способ починки nfs и dolphin. И еще стоит обратить внимание, что acl для nfs4 отличается. И именно поэтому стоит использовать nfs3 если у вас нет домена.]]></summary></entry><entry><title type="html">Linux: Создание rescue-записи grub в Fedora</title><link href="http://russianpenguin.ru/2024/10/22/regenerate-rescue-kernel" rel="alternate" type="text/html" title="Linux: Создание rescue-записи grub в Fedora" /><published>2024-10-22T00:00:00+03:00</published><updated>2024-10-22T00:00:00+03:00</updated><id>http://russianpenguin.ru/2024/10/22/regenerate-rescue-kernel</id><content type="html" xml:base="http://russianpenguin.ru/2024/10/22/regenerate-rescue-kernel"><![CDATA[<p>Для систем, которые существуют очень долго и обновляются через версии есть опасность того, что rescue ядро не заведётся. Вернее оно заведётся, но работать будет некомфортно.</p>

<p>А так как механизма обновления ядра в дефолте нет, то стоит производить его руками хотя бы раз в несколько версий дистрибутива.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">sudo rm</span> /boot/<span class="k">*</span>rescue<span class="k">*</span>
<span class="nv">$ </span><span class="nb">sudo</span> /usr/lib/kernel/install.d/51-dracut-rescue.install add <span class="s2">"</span><span class="si">$(</span><span class="nb">uname</span> <span class="nt">-r</span><span class="si">)</span><span class="s2">"</span> /boot <span class="s2">"/boot/vmlinuz-</span><span class="si">$(</span><span class="nb">uname</span> <span class="nt">-r</span><span class="si">)</span><span class="s2">"</span>
</code></pre></div></div>]]></content><author><name></name></author><category term="HowTo" /><category term="linux" /><summary type="html"><![CDATA[Для систем, которые существуют очень долго и обновляются через версии есть опасность того, что rescue ядро не заведётся. Вернее оно заведётся, но работать будет некомфортно. А так как механизма обновления ядра в дефолте нет, то стоит производить его руками хотя бы раз в несколько версий дистрибутива. $ sudo rm /boot/*rescue* $ sudo /usr/lib/kernel/install.d/51-dracut-rescue.install add "$(uname -r)" /boot "/boot/vmlinuz-$(uname -r)"]]></summary></entry><entry><title type="html">Python: парсим аргументы командной строки</title><link href="http://russianpenguin.ru/2024/10/01/python-argparse" rel="alternate" type="text/html" title="Python: парсим аргументы командной строки" /><published>2024-10-01T00:00:00+03:00</published><updated>2024-10-01T00:00:00+03:00</updated><id>http://russianpenguin.ru/2024/10/01/python-argparse</id><content type="html" xml:base="http://russianpenguin.ru/2024/10/01/python-argparse"><![CDATA[<p>Сегодня разберемся с сабпарсерами объекта <code class="language-plaintext highlighter-rouge">argparse.ArgumentParser</code>, которые передаются через параметр <code class="language-plaintext highlighter-rouge">parents</code>.</p>

<p>В общем случае при попытке распарсить аргументы командной строки мы создаем объект и начинаем методично добавлять к нему все известные нам параметры.</p>

<p>Иногда можно встретить очень большие листинги. Но существует механизм, который позволяет разбивать парсеры на более мелкие составляющие и сцеплять их между собой для более простого понимания (кстати, очень полезно при создании системы плагинов).</p>

<p>При этом мы можем управлять тем, какие аргументы будут парсится.</p>

<p>Для этого в параметры <code class="language-plaintext highlighter-rouge">parents</code> можно передать те объекты, от которых надо унаследоваться.</p>

<p>Рассмотрим на примерах.</p>

<p>В первом случае создается <code class="language-plaintext highlighter-rouge">ArgumentParser</code> с одним аргументом. И он сразу же разбирает командную строку на известные параметры и хвост при помощи <code class="language-plaintext highlighter-rouge">parse_known_args</code>.</p>

<p>В зависимости от значения <code class="language-plaintext highlighter-rouge">-l</code> мы либо продолжим работу, либо остановимся.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">argparse</span>  
  
<span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="p">.</span><span class="n">ArgumentParser</span><span class="p">(</span><span class="n">add_help</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>  
<span class="n">parser</span><span class="p">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s">'-l'</span><span class="p">,</span> <span class="s">'--list'</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s">"List something"</span><span class="p">,</span> <span class="n">action</span><span class="o">=</span><span class="s">'store_true'</span><span class="p">)</span>  
<span class="n">args</span><span class="p">,</span> <span class="n">remaining</span> <span class="o">=</span> <span class="n">parser</span><span class="p">.</span><span class="n">parse_known_args</span><span class="p">()</span>  
  
<span class="k">if</span> <span class="n">args</span><span class="p">.</span><span class="nb">list</span><span class="p">:</span>  
   <span class="k">print</span><span class="p">(</span><span class="s">'List'</span><span class="p">)</span>  
   <span class="nb">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>  
  
<span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="p">.</span><span class="n">ArgumentParser</span><span class="p">(</span>  
   <span class="n">description</span><span class="o">=</span><span class="s">"Chained parsers"</span><span class="p">,</span>  
   <span class="n">formatter_class</span><span class="o">=</span><span class="n">argparse</span><span class="p">.</span><span class="n">RawDescriptionHelpFormatter</span><span class="p">,</span>  
   <span class="n">parents</span><span class="o">=</span><span class="p">[</span><span class="n">parser</span><span class="p">])</span>  
  
<span class="n">parser</span><span class="p">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s">'-t'</span><span class="p">,</span> <span class="s">'--test'</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s">"Test"</span><span class="p">,</span> <span class="n">action</span><span class="o">=</span><span class="s">'store_true'</span><span class="p">)</span>  
<span class="n">other_args</span> <span class="o">=</span> <span class="n">parser</span><span class="p">.</span><span class="n">parse_args</span><span class="p">(</span><span class="n">remaining</span><span class="p">)</span>  
  
<span class="k">print</span><span class="p">(</span><span class="s">'Args: {}'</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">other_args</span><span class="p">))</span>
</code></pre></div></div>

<p>Второй пример чуть более сложный.</p>

<p>Допустим, что код обрабатывает видеофайлы и аудиофайлы. В зависимости от этого у него меняется поведение атрибута <code class="language-plaintext highlighter-rouge">-r</code>.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">argparse</span>  
<span class="kn">import</span> <span class="nn">enum</span>  
  
<span class="k">class</span> <span class="nc">Formats</span><span class="p">(</span><span class="n">enum</span><span class="p">.</span><span class="n">Enum</span><span class="p">):</span>  
   <span class="n">VIDEO</span><span class="o">=</span><span class="s">'video'</span>  
   <span class="n">AUDIO</span><span class="o">=</span><span class="s">'audio'</span>  
  
   <span class="k">def</span> <span class="nf">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>  
       <span class="k">return</span> <span class="bp">self</span><span class="p">.</span><span class="n">value</span>  
  
<span class="k">def</span> <span class="nf">parser_common</span><span class="p">():</span>  
   <span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="p">.</span><span class="n">ArgumentParser</span><span class="p">(</span><span class="n">add_help</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>  
   <span class="n">parser</span><span class="p">.</span><span class="n">add_argument</span><span class="p">(</span>  
       <span class="s">'-f'</span><span class="p">,</span> <span class="s">'--format'</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s">"Specify format"</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="n">Formats</span><span class="p">,</span> <span class="n">choices</span><span class="o">=</span><span class="nb">list</span><span class="p">(</span><span class="n">Formats</span><span class="p">)</span>  
   <span class="p">)</span>  
   <span class="k">return</span> <span class="n">parser</span>  
  
<span class="k">def</span> <span class="nf">parser_video</span><span class="p">(</span><span class="n">parent_parser</span><span class="p">:</span> <span class="n">argparse</span><span class="p">.</span><span class="n">ArgumentParser</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">argparse</span><span class="p">.</span><span class="n">ArgumentParser</span><span class="p">:</span>  
   <span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="p">.</span><span class="n">ArgumentParser</span><span class="p">(</span>  
       <span class="n">description</span><span class="o">=</span><span class="s">"Video parser"</span><span class="p">,</span>  
       <span class="n">formatter_class</span><span class="o">=</span><span class="n">argparse</span><span class="p">.</span><span class="n">RawDescriptionHelpFormatter</span><span class="p">,</span>  
       <span class="n">parents</span><span class="o">=</span><span class="p">[</span><span class="n">parent_parser</span><span class="p">])</span>  
   <span class="n">parser</span><span class="p">.</span><span class="n">add_argument</span><span class="p">(</span>  
       <span class="s">'-r'</span><span class="p">,</span>  
       <span class="s">'--resolution'</span><span class="p">,</span>  
       <span class="n">help</span><span class="o">=</span><span class="s">"Resolution"</span><span class="p">,</span>  
       <span class="nb">type</span><span class="o">=</span><span class="nb">int</span><span class="p">,</span>  
       <span class="n">nargs</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span>  
       <span class="n">metavar</span><span class="o">=</span><span class="p">(</span><span class="s">'WIDTH'</span><span class="p">,</span> <span class="s">'HEIGHT'</span><span class="p">),</span>  
       <span class="n">required</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span>  
   <span class="p">)</span>  
   <span class="k">return</span> <span class="n">parser</span>  
  
<span class="k">def</span> <span class="nf">parser_audio</span><span class="p">(</span><span class="n">parent_parser</span><span class="p">:</span> <span class="n">argparse</span><span class="p">.</span><span class="n">ArgumentParser</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">argparse</span><span class="p">.</span><span class="n">ArgumentParser</span><span class="p">:</span>  
   <span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="p">.</span><span class="n">ArgumentParser</span><span class="p">(</span>  
       <span class="n">description</span><span class="o">=</span><span class="s">"Audio parser"</span><span class="p">,</span>  
       <span class="n">formatter_class</span><span class="o">=</span><span class="n">argparse</span><span class="p">.</span><span class="n">RawDescriptionHelpFormatter</span><span class="p">,</span>  
       <span class="n">parents</span><span class="o">=</span><span class="p">[</span><span class="n">parent_parser</span><span class="p">])</span>  
   <span class="n">parser</span><span class="p">.</span><span class="n">add_argument</span><span class="p">(</span>  
       <span class="s">'-r'</span><span class="p">,</span>  
       <span class="s">'--resolution'</span><span class="p">,</span>  
       <span class="n">help</span><span class="o">=</span><span class="s">"Audit resolution"</span><span class="p">,</span>  
       <span class="nb">type</span><span class="o">=</span><span class="nb">int</span><span class="p">,</span>  
       <span class="n">required</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span>  
   <span class="p">)</span>  
   <span class="k">return</span> <span class="n">parser</span>  
  
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>  
   <span class="n">parser</span> <span class="o">=</span> <span class="n">parser_common</span><span class="p">()</span>  
   <span class="n">args</span><span class="p">,</span> <span class="n">remaining</span> <span class="o">=</span> <span class="n">parser</span><span class="p">.</span><span class="n">parse_known_args</span><span class="p">()</span>  
   <span class="k">if</span> <span class="n">args</span><span class="p">.</span><span class="nb">format</span> <span class="o">==</span> <span class="n">Formats</span><span class="p">.</span><span class="n">AUDIO</span><span class="p">:</span>  
       <span class="n">parser</span> <span class="o">=</span> <span class="n">parser_audio</span><span class="p">(</span><span class="n">parser</span><span class="p">)</span>  
   <span class="k">elif</span> <span class="n">args</span><span class="p">.</span><span class="nb">format</span> <span class="o">==</span> <span class="n">Formats</span><span class="p">.</span><span class="n">VIDEO</span><span class="p">:</span>  
       <span class="n">parser</span> <span class="o">=</span> <span class="n">parser_video</span><span class="p">(</span><span class="n">parser</span><span class="p">)</span>  
   <span class="k">else</span><span class="p">:</span>  
       <span class="n">parser</span><span class="p">.</span><span class="n">print_help</span><span class="p">()</span>  
       <span class="nb">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>  
  
   <span class="n">other_args</span> <span class="o">=</span> <span class="n">parser</span><span class="p">.</span><span class="n">parse_args</span><span class="p">(</span><span class="n">remaining</span><span class="p">)</span>  
   <span class="k">print</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>  
   <span class="k">print</span><span class="p">(</span><span class="s">'Args: {}'</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">other_args</span><span class="p">))</span>  
  
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">'__main__'</span><span class="p">:</span>  
   <span class="n">main</span><span class="p">()</span>
</code></pre></div></div>

<p>Запустите и посмотрите, как ведёт себя данный код.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>python argsparser.py
usage: argsparser.py <span class="o">[</span><span class="nt">-f</span> <span class="o">{</span>video,audio<span class="o">}]</span>

options:
  <span class="nt">-f</span> <span class="o">{</span>video,audio<span class="o">}</span>, <span class="nt">--format</span> <span class="o">{</span>video,audio<span class="o">}</span>
                        Specify format
<span class="nv">$ </span>python argsparser.py <span class="nt">-f</span> audio
usage: argsparser.py <span class="o">[</span><span class="nt">-h</span><span class="o">]</span> <span class="o">[</span><span class="nt">-f</span> <span class="o">{</span>video,audio<span class="o">}]</span> <span class="nt">-r</span> RESOLUTION
argsparser.py: error: the following arguments are required: <span class="nt">-r</span>/--resolution
<span class="nv">$ </span>python argsparser.py <span class="nt">-f</span> video
usage: argsparser.py <span class="o">[</span><span class="nt">-h</span><span class="o">]</span> <span class="o">[</span><span class="nt">-f</span> <span class="o">{</span>video,audio<span class="o">}]</span> <span class="nt">-r</span> WIDTH HEIGHT
argsparser.py: error: the following arguments are required: <span class="nt">-r</span>/--resolution
<span class="nv">$ </span>python argsparser.py <span class="nt">-f</span> video <span class="nt">-h</span>
usage: argsparser.py <span class="o">[</span><span class="nt">-h</span><span class="o">]</span> <span class="o">[</span><span class="nt">-f</span> <span class="o">{</span>video,audio<span class="o">}]</span> <span class="nt">-r</span> WIDTH HEIGHT

Video parser

options:
  <span class="nt">-h</span>, <span class="nt">--help</span>            show this <span class="nb">help </span>message and <span class="nb">exit</span>
  <span class="nt">-f</span> <span class="o">{</span>video,audio<span class="o">}</span>, <span class="nt">--format</span> <span class="o">{</span>video,audio<span class="o">}</span>
                        Specify format
  <span class="nt">-r</span> WIDTH HEIGHT, <span class="nt">--resolution</span> WIDTH HEIGHT
                        Resolution
<span class="nv">$ </span>python argsparser.py <span class="nt">-f</span> audio <span class="nt">-h</span>
usage: argsparser.py <span class="o">[</span><span class="nt">-h</span><span class="o">]</span> <span class="o">[</span><span class="nt">-f</span> <span class="o">{</span>video,audio<span class="o">}]</span> <span class="nt">-r</span> RESOLUTION

Audio parser

options:
  <span class="nt">-h</span>, <span class="nt">--help</span>            show this <span class="nb">help </span>message and <span class="nb">exit</span>
  <span class="nt">-f</span> <span class="o">{</span>video,audio<span class="o">}</span>, <span class="nt">--format</span> <span class="o">{</span>video,audio<span class="o">}</span>
                        Specify format
  <span class="nt">-r</span> RESOLUTION, <span class="nt">--resolution</span> RESOLUTION
                        Audit resolution

</code></pre></div></div>]]></content><author><name></name></author><category term="HowTo" /><category term="python" /><category term="console" /><summary type="html"><![CDATA[Сегодня разберемся с сабпарсерами объекта argparse.ArgumentParser, которые передаются через параметр parents. В общем случае при попытке распарсить аргументы командной строки мы создаем объект и начинаем методично добавлять к нему все известные нам параметры. Иногда можно встретить очень большие листинги. Но существует механизм, который позволяет разбивать парсеры на более мелкие составляющие и сцеплять их между собой для более простого понимания (кстати, очень полезно при создании системы плагинов). При этом мы можем управлять тем, какие аргументы будут парсится. Для этого в параметры parents можно передать те объекты, от которых надо унаследоваться. Рассмотрим на примерах. В первом случае создается ArgumentParser с одним аргументом. И он сразу же разбирает командную строку на известные параметры и хвост при помощи parse_known_args. В зависимости от значения -l мы либо продолжим работу, либо остановимся. import argparse parser = argparse.ArgumentParser(add_help=False) parser.add_argument('-l', '--list', help="List something", action='store_true') args, remaining = parser.parse_known_args() if args.list: print('List') exit(0) parser = argparse.ArgumentParser( description="Chained parsers", formatter_class=argparse.RawDescriptionHelpFormatter, parents=[parser]) parser.add_argument('-t', '--test', help="Test", action='store_true') other_args = parser.parse_args(remaining) print('Args: {}'.format(other_args)) Второй пример чуть более сложный. Допустим, что код обрабатывает видеофайлы и аудиофайлы. В зависимости от этого у него меняется поведение атрибута -r. import argparse import enum class Formats(enum.Enum): VIDEO='video' AUDIO='audio' def __str__(self): return self.value def parser_common(): parser = argparse.ArgumentParser(add_help=False) parser.add_argument( '-f', '--format', help="Specify format", type=Formats, choices=list(Formats) ) return parser def parser_video(parent_parser: argparse.ArgumentParser) -&gt; argparse.ArgumentParser: parser = argparse.ArgumentParser( description="Video parser", formatter_class=argparse.RawDescriptionHelpFormatter, parents=[parent_parser]) parser.add_argument( '-r', '--resolution', help="Resolution", type=int, nargs=2, metavar=('WIDTH', 'HEIGHT'), required=True, ) return parser def parser_audio(parent_parser: argparse.ArgumentParser) -&gt; argparse.ArgumentParser: parser = argparse.ArgumentParser( description="Audio parser", formatter_class=argparse.RawDescriptionHelpFormatter, parents=[parent_parser]) parser.add_argument( '-r', '--resolution', help="Audit resolution", type=int, required=True, ) return parser def main(): parser = parser_common() args, remaining = parser.parse_known_args() if args.format == Formats.AUDIO: parser = parser_audio(parser) elif args.format == Formats.VIDEO: parser = parser_video(parser) else: parser.print_help() exit(1) other_args = parser.parse_args(remaining) print(2) print('Args: {}'.format(other_args)) if __name__ == '__main__': main() Запустите и посмотрите, как ведёт себя данный код. $ python argsparser.py usage: argsparser.py [-f {video,audio}] options: -f {video,audio}, --format {video,audio} Specify format $ python argsparser.py -f audio usage: argsparser.py [-h] [-f {video,audio}] -r RESOLUTION argsparser.py: error: the following arguments are required: -r/--resolution $ python argsparser.py -f video usage: argsparser.py [-h] [-f {video,audio}] -r WIDTH HEIGHT argsparser.py: error: the following arguments are required: -r/--resolution $ python argsparser.py -f video -h usage: argsparser.py [-h] [-f {video,audio}] -r WIDTH HEIGHT Video parser options: -h, --help show this help message and exit -f {video,audio}, --format {video,audio} Specify format -r WIDTH HEIGHT, --resolution WIDTH HEIGHT Resolution $ python argsparser.py -f audio -h usage: argsparser.py [-h] [-f {video,audio}] -r RESOLUTION Audio parser options: -h, --help show this help message and exit -f {video,audio}, --format {video,audio} Specify format -r RESOLUTION, --resolution RESOLUTION Audit resolution]]></summary></entry><entry><title type="html">SDDM: Переключаем раскладку автоматически при блокировании экрана</title><link href="http://russianpenguin.ru/2024/08/08/kde-switch-keyboad-layout-from-systemd" rel="alternate" type="text/html" title="SDDM: Переключаем раскладку автоматически при блокировании экрана" /><published>2024-08-08T00:00:00+03:00</published><updated>2024-08-08T00:00:00+03:00</updated><id>http://russianpenguin.ru/2024/08/08/kde-switch-keyboad-layout-from-systemd</id><content type="html" xml:base="http://russianpenguin.ru/2024/08/08/kde-switch-keyboad-layout-from-systemd"><![CDATA[<p>Продолжаем разбираться с окном логина (sddm, gdm и прочие *dm).</p>

<p>В предудущей части мы <a href="/2024/08/07/kde-switch-keyboad-layout-from-cli">научились</a> переключать раскладку из консоли минуя кнопки и мышки.</p>

<p>А теперь мы научимся менять раскладку автоматически при блокировании экрана.</p>

<p>Зачем это нужно? Чаще всего пароль у нас на латинице. А заблокировать экран можно при любой включенной раскладке. Это приводит к тому, что на экране логина эту самую раскладку на до менать. Неудобно!</p>

<h2 id="1-определяем-когда-система-была-заблокирована">1. Определяем, когда система была заблокирована</h2>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/usr/bin/env bash</span>

dbus-monitor <span class="nt">--session</span> <span class="s2">"type='signal',interface='org.freedesktop.ScreenSaver'"</span> |
  <span class="k">while </span><span class="nb">read </span>x<span class="p">;</span> <span class="k">do
    case</span> <span class="s2">"</span><span class="nv">$x</span><span class="s2">"</span> <span class="k">in</span> 
      <span class="k">*</span><span class="s2">"boolean true"</span><span class="k">*</span><span class="p">)</span> <span class="nb">echo </span>SCREEN_LOCKED<span class="p">;;</span>
      <span class="k">*</span><span class="s2">"boolean false"</span><span class="k">*</span><span class="p">)</span> <span class="nb">echo </span>SCREEN_UNLOCKED<span class="p">;;</span>  
    <span class="k">esac</span>
  <span class="k">done</span>
</code></pre></div></div>

<p>Если запустить скрипт, заблокировать, а потом разблокировать экран, то мы увидим его работу.</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>SCREEN_LOCKED
SCREEN_LOCKED
SCREEN_UNLOCKED
SCREEN_UNLOCKED
</code></pre></div></div>

<p>Два сообщения из-за особенностей интерфейса. Можно привязываться к другому интерфейсу, но в данном случае это некритично.</p>

<h2 id="2-учимся-запускать-скрипт-фоном-через-systemd">2. Учимся запускать скрипт фоном через systemd</h2>

<p>Делаем скрипт <code class="language-plaintext highlighter-rouge">/.local/bin/set-layout-on-lock</code>. Не забывайте поставить на него `+x .</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/usr/bin/env bash</span>

dbus-monitor <span class="nt">--session</span> <span class="s2">"type='signal',interface='org.freedesktop.ScreenSaver'"</span> |
  <span class="k">while </span><span class="nb">read </span>x<span class="p">;</span> <span class="k">do
    case</span> <span class="s2">"</span><span class="nv">$x</span><span class="s2">"</span> <span class="k">in</span> 
      <span class="k">*</span><span class="s2">"boolean true"</span><span class="k">*</span><span class="p">)</span> qdbus org.kde.keyboard /Layouts org.kde.KeyboardLayouts.setLayout 0<span class="p">;;</span>
      <span class="k">*</span><span class="s2">"boolean false"</span><span class="k">*</span><span class="p">)</span> <span class="nb">echo </span>SCREEN_UNLOCKED<span class="p">;;</span>  
    <span class="k">esac</span>
  <span class="k">done</span>

</code></pre></div></div>

<p>Создаём каталог для сервисов systemd.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">mkdir</span> <span class="nt">-p</span> <span class="k">${</span><span class="nv">HOME</span><span class="k">}</span>/.config/systemd/user
</code></pre></div></div>

<p>Пишем сервис в <code class="language-plaintext highlighter-rouge">${HOME}/.config/systemd/user/set-kbd-layout-on-lock.service</code>.</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Unit]
Description=Set custom locale on screen lock

[Service]
Restart=always
ExecStart=%h/.local/bin/set-layout-on-lock

[Install]
WantedBy=graphical-session.target
</code></pre></div></div>

<ul>
  <li><code class="language-plaintext highlighter-rouge">%h</code> - означает директорию текущего пользователя.</li>
  <li><code class="language-plaintext highlighter-rouge">graphical-session.target</code> - означает, что сервис будет запускаться только с графическим интерфейсом (не нужен он нам в консоли).</li>
</ul>

<h2 id="3-включаем">3. Включаем</h2>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>systemctl <span class="nt">--user</span> <span class="nb">enable</span> <span class="nt">--now</span> set-kbd-layout-on-lock
</code></pre></div></div>

<p>Сервис будет включен и тут же запущен.</p>

<p>Посмотреть состояние можно командой <code class="language-plaintext highlighter-rouge">status</code>.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>systemctl <span class="nt">--user</span> status set-kbd-layout-on-lock
</code></pre></div></div>

<h2 id="литература">Литература</h2>
<ul>
  <li><a href="https://www.freedesktop.org/software/systemd/man/latest/systemd.unit.html#Specifiers">man systemd.unit</a></li>
</ul>]]></content><author><name></name></author><category term="HowTo" /><category term="linux" /><category term="systemd" /><category term="dbus" /><summary type="html"><![CDATA[Продолжаем разбираться с окном логина (sddm, gdm и прочие *dm). В предудущей части мы научились переключать раскладку из консоли минуя кнопки и мышки. А теперь мы научимся менять раскладку автоматически при блокировании экрана. Зачем это нужно? Чаще всего пароль у нас на латинице. А заблокировать экран можно при любой включенной раскладке. Это приводит к тому, что на экране логина эту самую раскладку на до менать. Неудобно! 1. Определяем, когда система была заблокирована #!/usr/bin/env bash dbus-monitor --session "type='signal',interface='org.freedesktop.ScreenSaver'" | while read x; do case "$x" in *"boolean true"*) echo SCREEN_LOCKED;; *"boolean false"*) echo SCREEN_UNLOCKED;; esac done Если запустить скрипт, заблокировать, а потом разблокировать экран, то мы увидим его работу. SCREEN_LOCKED SCREEN_LOCKED SCREEN_UNLOCKED SCREEN_UNLOCKED Два сообщения из-за особенностей интерфейса. Можно привязываться к другому интерфейсу, но в данном случае это некритично. 2. Учимся запускать скрипт фоном через systemd Делаем скрипт /.local/bin/set-layout-on-lock. Не забывайте поставить на него `+x . #!/usr/bin/env bash dbus-monitor --session "type='signal',interface='org.freedesktop.ScreenSaver'" | while read x; do case "$x" in *"boolean true"*) qdbus org.kde.keyboard /Layouts org.kde.KeyboardLayouts.setLayout 0;; *"boolean false"*) echo SCREEN_UNLOCKED;; esac done Создаём каталог для сервисов systemd. $ mkdir -p ${HOME}/.config/systemd/user Пишем сервис в ${HOME}/.config/systemd/user/set-kbd-layout-on-lock.service. [Unit] Description=Set custom locale on screen lock [Service] Restart=always ExecStart=%h/.local/bin/set-layout-on-lock [Install] WantedBy=graphical-session.target %h - означает директорию текущего пользователя. graphical-session.target - означает, что сервис будет запускаться только с графическим интерфейсом (не нужен он нам в консоли). 3. Включаем $ systemctl --user enable --now set-kbd-layout-on-lock Сервис будет включен и тут же запущен. Посмотреть состояние можно командой status. $ systemctl --user status set-kbd-layout-on-lock Литература man systemd.unit]]></summary></entry><entry><title type="html">KDE: Переключаем раскладку из консоли</title><link href="http://russianpenguin.ru/2024/08/07/kde-switch-keyboad-layout-from-cli" rel="alternate" type="text/html" title="KDE: Переключаем раскладку из консоли" /><published>2024-08-07T00:00:00+03:00</published><updated>2024-08-07T00:00:00+03:00</updated><id>http://russianpenguin.ru/2024/08/07/kde-switch-keyboad-layout-from-cli</id><content type="html" xml:base="http://russianpenguin.ru/2024/08/07/kde-switch-keyboad-layout-from-cli"><![CDATA[<p>Очень полезной штукой является возможность переключить раскладку из консоли.</p>

<p>Зачем? Например, при блокировании сеанса надо сделать так, чтобы раскладка стала английской.</p>

<p>Так как дистрибутивы очень сильно видоизменились и стали поставляться с wayland и производными systemd (keyboad, logind, …), то переключать стандартными линуксовыми средствами вроде setxkbmap, xkb-switch и прочими способами не получиться.</p>

<p>Теперь раскладка в дистрибутивах переключается при помощи dbus и сигналов.</p>

<p>Для kde это делается вызовом метода <code class="language-plaintext highlighter-rouge">org.kde.KeyboardLayouts.setLayout</code> в сервисе <code class="language-plaintext highlighter-rouge">org.kde.keyboard</code>.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>qdbus org.kde.keyboard /Layouts org.kde.KeyboardLayouts.setLayout 1
</code></pre></div></div>

<p><img class="img-fluid" src="/assets/images/2024/kde-switch-keyboad-layout-from-cli/animation.gif" alt="Layout switch" title="Layout switch" /></p>

<p>Последний аргумент - это номер раскладки в списке.</p>

<p>Посмотреть список раскладок можно через другой метод.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>qdbus <span class="nt">--literal</span> org.kde.keyboard /Layouts org.kde.KeyboardLayouts.getLayoutsList
<span class="o">[</span>Argument: a<span class="o">(</span>sss<span class="o">)</span> <span class="o">{[</span>Argument: <span class="o">(</span>sss<span class="o">)</span> <span class="s2">"us"</span>, <span class="s2">""</span>, <span class="s2">"Английская (США)"</span><span class="o">]</span>, <span class="o">[</span>Argument: <span class="o">(</span>sss<span class="o">)</span> <span class="s2">"ru"</span>, <span class="s2">""</span>, <span class="s2">"Русская"</span><span class="o">]}]</span>
</code></pre></div></div>

<p>Обязательный аргумент в нашем случае - это <code class="language-plaintext highlighter-rouge">--literal</code>. Без него команда просто выведет сообщение о том, что не может отобразить нестандарный тип данных.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>qdbus org.kde.keyboard /Layouts org.kde.KeyboardLayouts.getLayoutsList
qdbus: I don<span class="s1">'t know how to display an argument of type '</span>a<span class="o">(</span>sss<span class="o">)</span><span class="s1">', run with --literal.
</span></code></pre></div></div>]]></content><author><name></name></author><category term="HowTo" /><category term="linux" /><category term="kde" /><category term="dbus" /><summary type="html"><![CDATA[Очень полезной штукой является возможность переключить раскладку из консоли. Зачем? Например, при блокировании сеанса надо сделать так, чтобы раскладка стала английской. Так как дистрибутивы очень сильно видоизменились и стали поставляться с wayland и производными systemd (keyboad, logind, …), то переключать стандартными линуксовыми средствами вроде setxkbmap, xkb-switch и прочими способами не получиться. Теперь раскладка в дистрибутивах переключается при помощи dbus и сигналов. Для kde это делается вызовом метода org.kde.KeyboardLayouts.setLayout в сервисе org.kde.keyboard. $ qdbus org.kde.keyboard /Layouts org.kde.KeyboardLayouts.setLayout 1 Последний аргумент - это номер раскладки в списке. Посмотреть список раскладок можно через другой метод. $ qdbus --literal org.kde.keyboard /Layouts org.kde.KeyboardLayouts.getLayoutsList [Argument: a(sss) {[Argument: (sss) "us", "", "Английская (США)"], [Argument: (sss) "ru", "", "Русская"]}] Обязательный аргумент в нашем случае - это --literal. Без него команда просто выведет сообщение о том, что не может отобразить нестандарный тип данных. $ qdbus org.kde.keyboard /Layouts org.kde.KeyboardLayouts.getLayoutsList qdbus: I don't know how to display an argument of type 'a(sss)', run with --literal.]]></summary></entry><entry><title type="html">Linux: Система засыпает при заблокированном сеансе</title><link href="http://russianpenguin.ru/2024/05/10/linux-sleep-on-login-screen" rel="alternate" type="text/html" title="Linux: Система засыпает при заблокированном сеансе" /><published>2024-05-10T00:00:00+03:00</published><updated>2024-05-10T00:00:00+03:00</updated><id>http://russianpenguin.ru/2024/05/10/linux-sleep-on-login-screen</id><content type="html" xml:base="http://russianpenguin.ru/2024/05/10/linux-sleep-on-login-screen"><![CDATA[<p>Gnome и Kde страдают тем, что на экране логина за электропитание отвечает не утилита управления электропитанием, а logind из состава systemd и настроить поведение компьютера в этом режиме в панелях управления нельзя.</p>

<p>Проблема наблюдается как в gdm, так и sddm.</p>

<p>Проявляется в следующих случаях:</p>
<ul>
  <li>Включили машину, но не вошли в систему <strong>-&gt;</strong> компьютер ушел в спячку</li>
  <li>Включили ноутбук с внешним монитором, поработали и заблокировали сеанс <strong>-&gt;</strong> система ушла в спячку если закрыть крышку</li>
</ul>

<p>Есть даже много отчетов об ошибках и информация от разработчиков о том, что это сделано “ради прохождения сертификации энергопотребления”.</p>

<ul>
  <li><a href="https://github.com/sddm/sddm/issues/1148">Баг в sddm на экране логина</a></li>
  <li><a href="https://discussion.fedoraproject.org/t/gnome-suspends-after-15-minutes-of-user-inactivity-even-on-ac-power/79801">Прохождение сертификации Fedora</a></li>
</ul>

<p>Чтобы избежать засыпания системы после включения нужно сконфигурировать gdm отключив ему спячку (sddm, lxdm и т.п. работают нормально).</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo</span> <span class="nt">-u</span> gdm dbus-run-session gsettings <span class="nb">set </span>org.gnome.settings-daemon.plugins.power sleep-inactive-ac-timeout 0
</code></pre></div></div>

<p>Чтобы избежать проблемы засыпания ноутбука при закрытой крышке нужно дополнительно прописать настройки в <code class="language-plaintext highlighter-rouge">/etc/systemd/login.conf.d/00-lid.conf</code> или же в <code class="language-plaintext highlighter-rouge">/etc/systemd/login.conf</code>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Login]  
HandleLidSwitchExternalPower=ignore  
HandleLidSwitchDocked=ignore
</code></pre></div></div>]]></content><author><name></name></author><category term="HowTo" /><category term="linux" /><summary type="html"><![CDATA[Gnome и Kde страдают тем, что на экране логина за электропитание отвечает не утилита управления электропитанием, а logind из состава systemd и настроить поведение компьютера в этом режиме в панелях управления нельзя. Проблема наблюдается как в gdm, так и sddm. Проявляется в следующих случаях: Включили машину, но не вошли в систему -&gt; компьютер ушел в спячку Включили ноутбук с внешним монитором, поработали и заблокировали сеанс -&gt; система ушла в спячку если закрыть крышку Есть даже много отчетов об ошибках и информация от разработчиков о том, что это сделано “ради прохождения сертификации энергопотребления”. Баг в sddm на экране логина Прохождение сертификации Fedora Чтобы избежать засыпания системы после включения нужно сконфигурировать gdm отключив ему спячку (sddm, lxdm и т.п. работают нормально). sudo -u gdm dbus-run-session gsettings set org.gnome.settings-daemon.plugins.power sleep-inactive-ac-timeout 0 Чтобы избежать проблемы засыпания ноутбука при закрытой крышке нужно дополнительно прописать настройки в /etc/systemd/login.conf.d/00-lid.conf или же в /etc/systemd/login.conf. [Login] HandleLidSwitchExternalPower=ignore HandleLidSwitchDocked=ignore]]></summary></entry><entry><title type="html">IDEA: Не работает превью для Markdown</title><link href="http://russianpenguin.ru/2024/01/09/no-markdown-preview-in-idea" rel="alternate" type="text/html" title="IDEA: Не работает превью для Markdown" /><published>2024-01-19T00:00:00+03:00</published><updated>2024-01-19T00:00:00+03:00</updated><id>http://russianpenguin.ru/2024/01/09/no-markdown-preview-in-idea</id><content type="html" xml:base="http://russianpenguin.ru/2024/01/09/no-markdown-preview-in-idea"><![CDATA[<p><img class="img-fluid" src="/assets/images/2024/markdown_idea/1.png" alt="There are no available preview providers" title="There are no available preview providers" /></p>

<p>Есть вероятность, что возможность смотреть превью markdown-файлов в соответствующем <a href="https://www.jetbrains.com/help/idea/markdown.html">плагине</a> отсутствует.</p>

<p>Скорее всего проблема в jdk и jfx, которые вы используете. Чаще всего используются те, что идут бандлом с самое ide.</p>

<p>Нужно поменять:</p>
<ul>
  <li>идем в быстрый поиск (двойное нажатие shift)</li>
  <li>вбиваем <em>choose boot java runtime for ide</em></li>
  <li>выбираем другую версию jdk c jcef</li>
  <li>плагин должен заработать корректно</li>
  <li>если не случилось - повторяем (можно использовать системный jre)</li>
</ul>

<p><img class="img-fluid" src="/assets/images/2024/markdown_idea/2.png" alt="Choose JRE" title="Choose JRD" /></p>

<p><img class="img-fluid" src="/assets/images/2024/markdown_idea/3.png" alt="Choose new version" title="Choose new version" /></p>

<p><img class="img-fluid" src="/assets/images/2024/markdown_idea/4.png" alt="Done" title="Done" /></p>]]></content><author><name></name></author><category term="HowTo" /><category term="linux" /><category term="idea" /><category term="java" /><summary type="html"><![CDATA[Есть вероятность, что возможность смотреть превью markdown-файлов в соответствующем плагине отсутствует. Скорее всего проблема в jdk и jfx, которые вы используете. Чаще всего используются те, что идут бандлом с самое ide. Нужно поменять: идем в быстрый поиск (двойное нажатие shift) вбиваем choose boot java runtime for ide выбираем другую версию jdk c jcef плагин должен заработать корректно если не случилось - повторяем (можно использовать системный jre)]]></summary></entry></feed>