Sat, Apr 13, 2013
Matwey Kornilov
posted at
11:59
Диагностика ядра Linux
Сбои в ядре Linux приводят к возникновению чрезвычайно разнообразных симптомов. Некоторые авторы дают следующую неполную классификацию проблем, с которыми может столкнуться пользователь:
К счастью, ядро обладает неким набором средств первичной самодиагностики, пригодным для постановки примерного диагноза. Согласно, видимо всеобщей, философской парадигме, наиболее устойчивыми и надежными являются наиболее простые подсистемы, поэтому сообщения ядра имеет смысл искать в текстовой и последовательной консолях. Конечно, при достаточном уровне везения нужное сообщение будет сброшено syslog-демону, записано на диск, отправлено по сети на удаленный syslog-демон и прочее, но при недостаточном везении монитор (и фотоаппарат на телефоне), клавиатура и COM-порт являются последней надеждой.
Одним из механизмов общения ядра с внешним миром является printk. При неправильной настройке сообщение скорее всего будет просто потеряно как не обладающее значимостью. Для настройки используется /proc/sys/kernel/printk, соответствующий ему параметр sysctl, утилита klogconsole, SysRq-клавиша и т.п. Ядро обладает восемью уровнями важности сообщений, поэтому установка уровня в 8 заведомо напечатает все на консоль.
Магическая кнопка включается в /proc/sys/kernel/sysrq или соответствующим ему параметром sysctl. Предлагается просто записать туда 1, несмотря на то, что новые ядра позволяют изысканный контроль над функционалом. В данной ситуации незачем себя ограничивать, хотя для нормальной работы разумно ограничить функционал на случай случайных нажатий. Если осталась рабочая терминальная сессия (например удаленная сессия по ssh), можно использовать как альтернативу, например, echo b > /proc/sysrq-trigger; с последовательной консоли поведение активируется кнопкой 'break'.
Важно помнить, что SysRq-w, например, выдает сообщение с уровнем KERN_INFO, то есть выдача printk должна быть настроена правильно, чтобы можно было что-то увидеть. Полный список команд SysRq.
Параметр ядра softlockup_panic или параметр kernel.softlockup_panic для sysctl включают панику ядра при обнаружении soft lockup. Описание внутреннего устройства. Включение паники позволит остановить выполнение системы и проанализировать выдачу, снабженную трассировкой, хотя контроль блокировки исполняется постоянно. Существует аналогичный механизм отслеживания hard lockup для многопроцессорных систем (если остались живые процессоры — есть шанс что сработает), с соответствующим параметром hardlockup_panic. Время срабатывания обычно в пределах одной минуты.
Механизм отслеживания процессов, надолго застрявших в состоянии TASK_UNINTERRUPTIBLE, параметры настраиваются через sysctl и /proc:
- kernel oops — проблема при выполнении кода в ядре, например кто-нибудь попытался разыменовать нулевой указатель. С кем из программистов на C такого не случалось?
- kernel panic — кто-то попытался разыменовать нулевой указатель в обработчике прерываний. После чего ядро уходит в полную несознанку и начинает мигать caps-lock-ом.
- soft lockup — что-то заблокировалось (вероятно наткнувшись на не освобожденную блокировку), несмотря на это прерывания продолжают обрабатываться. Хорошее упражнение — попинговать машину или попытаться зажечь numlock.
- hard lockup — компьютер жужжит вентиляторами и ни на что не реагирует. Провести какую-то диагностику в этом случае особенно сложно. Проблема может быть вызвана как вышедшим из строя железом, так и неаккуратной обработкой прерываний.
- hung — индуцированное неправильной блокировкой последовательное попадание всех или большинства процессов системы в состояние TASK_UNINTERRUPTIBLE (известного так-же как D-состояние, по обозначению в top или ps). Согласно книге Р.Лава такой «наводящий ужас» процесс нельзя убить, завершить, и вообще что-то с ним сделать. При этом с точки зрения пространства пользователя программа просто заблокирована на каком-то системном вызове (например ввода-вывода). При попадании в подобное состояние всех критических процессов системы можно получить симптом похожий на soft lockup.
К счастью, ядро обладает неким набором средств первичной самодиагностики, пригодным для постановки примерного диагноза. Согласно, видимо всеобщей, философской парадигме, наиболее устойчивыми и надежными являются наиболее простые подсистемы, поэтому сообщения ядра имеет смысл искать в текстовой и последовательной консолях. Конечно, при достаточном уровне везения нужное сообщение будет сброшено syslog-демону, записано на диск, отправлено по сети на удаленный syslog-демон и прочее, но при недостаточном везении монитор (и фотоаппарат на телефоне), клавиатура и COM-порт являются последней надеждой.
printk
Одним из механизмов общения ядра с внешним миром является printk. При неправильной настройке сообщение скорее всего будет просто потеряно как не обладающее значимостью. Для настройки используется /proc/sys/kernel/printk, соответствующий ему параметр sysctl, утилита klogconsole, SysRq-клавиша и т.п. Ядро обладает восемью уровнями важности сообщений, поэтому установка уровня в 8 заведомо напечатает все на консоль.
sysrq
Магическая кнопка включается в /proc/sys/kernel/sysrq или соответствующим ему параметром sysctl. Предлагается просто записать туда 1, несмотря на то, что новые ядра позволяют изысканный контроль над функционалом. В данной ситуации незачем себя ограничивать, хотя для нормальной работы разумно ограничить функционал на случай случайных нажатий. Если осталась рабочая терминальная сессия (например удаленная сессия по ssh), можно использовать как альтернативу, например, echo b > /proc/sysrq-trigger; с последовательной консоли поведение активируется кнопкой 'break'.
Важно помнить, что SysRq-w, например, выдает сообщение с уровнем KERN_INFO, то есть выдача printk должна быть настроена правильно, чтобы можно было что-то увидеть. Полный список команд SysRq.
softlockup_panic
Параметр ядра softlockup_panic или параметр kernel.softlockup_panic для sysctl включают панику ядра при обнаружении soft lockup. Описание внутреннего устройства. Включение паники позволит остановить выполнение системы и проанализировать выдачу, снабженную трассировкой, хотя контроль блокировки исполняется постоянно. Существует аналогичный механизм отслеживания hard lockup для многопроцессорных систем (если остались живые процессоры — есть шанс что сработает), с соответствующим параметром hardlockup_panic. Время срабатывания обычно в пределах одной минуты.
hung_task_timeout_sec
Механизм отслеживания процессов, надолго застрявших в состоянии TASK_UNINTERRUPTIBLE, параметры настраиваются через sysctl и /proc:
- kernel.hung_task_panic — включает/отключает панику при обнаружении не прерываемого процесса;
- kernel.hung_task_warnings — счетчик сообщений. Иными словами, если паника отключена, будет сообщено о таком количестве зависших процессов;
- kernel.hung_task_timeout_secs — сколько секунд процесс должен непрерывно пробыть в TASK_UNINTERRUPTIBLE, чтобы вызвать сообщение. По умолчанию бывает либо выключено (0), либо очень большое число порядка 10 минут.
Sun, Feb 24, 2013
Matwey Kornilov
posted at
11:35
svn+ssh: коллективные соединения
При командах выполняемых на удаленном URL, типа copy или merge, subversion иногда требует несколько соединений. Для облегчения работы, можно применить стандартную возможность ssh — использовать одно TCP/IP соединение для нескольких сессий.
Чтобы не испортить настройки клиентского ssh, в секции [tunnels] файла конфигурации ~/.subversion/config зададим нужные настройки как параметры командной строки:
При этом соединение будет создаваться каждый раз при необходимости, и закрываться через 60 секунд после того, как оно становится невостребованным. ControlPersist=yes оставит соединение навсегда, что, вероятно, не очень безопасно, но зато позволяет комфортно исполнять разные команды, типа commit или update в течении работы, если расходы на создание соединения велики.
Чтобы не испортить настройки клиентского ssh, в секции [tunnels] файла конфигурации ~/.subversion/config зададим нужные настройки как параметры командной строки:
ssh = $SVN_SSH ssh -o "ControlMaster=auto" -o "ControlPath=/home/user/.ssh/svn_ssh-%r@%h:%p" -o "ControlPersist=60"
При этом соединение будет создаваться каждый раз при необходимости, и закрываться через 60 секунд после того, как оно становится невостребованным. ControlPersist=yes оставит соединение навсегда, что, вероятно, не очень безопасно, но зато позволяет комфортно исполнять разные команды, типа commit или update в течении работы, если расходы на создание соединения велики.
Sun, Feb 17, 2013
Matwey Kornilov
posted at
07:51
quilt и rpm
quilt — это система контроля патчей, в каком-то смысле предыдущая ступень эволюции систем контроля версий.
Пусть есть rpm-пакет и нужно обновить его версию, используя новый архив исходных кодов. При этом патчи останутся старыми, и не гарантируется, что они наложатся на новую версию, или не потребуется вмешательство человека, из-за того, что какой-то патч устарел. После того, как новый архив получен и Version: исправлен, можно прибегнуть к помощи quilt:
Эта команда создаст новую директорию в которой будут лежать распакованные исходные коды, символическая ссылка на директорию patches (хранит сами файлы патчей) и файл series (хранит порядок в котором патчи нужно применять). quilt не всегда успешно справляется с патчами, которые завернуты в %if.
Идеологически происходит следующее, у нас есть команда quilt, что-то вроде аналога git или hg, дерево исходников и стек патчей. Стек патчей в чем-то аналогичен ревизиям в системах контроля версий. Используя стек можно переходить от текущего состояния к следующему (применяя патч, quilt push) или к предыдущему (откатывая, quilt pop). Первоначально, мы находимся в самом нижнем состоянии (не модифицированные исходные коды):
Дальше попробуем наложить первый патч (здесь потребовалась предварительная обработка из-за хитрой структуры директорий в конкретном случае),
И так далее, пока не закончится весь стек патчей, но скорее всего так просто он не закончится. Задача — обновляя патчи, устранить конфликты. После принудительного применения (quilt push -f) следует вручную просмотреть все конфликтные места и исправить их нужным образом. Каждый патч отслеживает только некоторое число файлов (quilt files), но если отредактирован файл не из списка, то его нужно добавить (quilt add). После того как все исправлено, нужно обновить текущий патч: quilt refresh (это такой аналог commit, который исправляет текущий наложенный патч, основываясь на рабочей директории и предыдущей спрятанной копии)
Пусть есть rpm-пакет и нужно обновить его версию, используя новый архив исходных кодов. При этом патчи останутся старыми, и не гарантируется, что они наложатся на новую версию, или не потребуется вмешательство человека, из-за того, что какой-то патч устарел. После того, как новый архив получен и Version: исправлен, можно прибегнуть к помощи quilt:
quilt setup libdc1394.spec
Эта команда создаст новую директорию в которой будут лежать распакованные исходные коды, символическая ссылка на директорию patches (хранит сами файлы патчей) и файл series (хранит порядок в котором патчи нужно применять). quilt не всегда успешно справляется с патчами, которые завернуты в %if.
Идеологически происходит следующее, у нас есть команда quilt, что-то вроде аналога git или hg, дерево исходников и стек патчей. Стек патчей в чем-то аналогичен ревизиям в системах контроля версий. Используя стек можно переходить от текущего состояния к следующему (применяя патч, quilt push) или к предыдущему (откатывая, quilt pop). Первоначально, мы находимся в самом нижнем состоянии (не модифицированные исходные коды):
>quilt top Нет применённых патчей >quilt applied Нет применённых патчей >quilt unapplied patches/libdc1394.no-x11.patch patches/libdc1394.ac.patch patches/libdc1394-swab_fix.patch patches/libdc1394.raw1394_set_iso_handler.patch patches/libdc1394-v4l-2.6.38.patch patches/libdc1394-visibility.patch
Дальше попробуем наложить первый патч (здесь потребовалась предварительная обработка из-за хитрой структуры директорий в конкретном случае),
>quilt push Наложение патча patches/libdc1394.no-x11.patch patching file libdc1394-1.2.2/examples/Makefile.am patching file libdc1394-2.2.1/configure.in Текущий патч: patches/libdc1394.no-x11.patch >quilt top patches/libdc1394.no-x11.patch >quilt applied patches/libdc1394.no-x11.patch
И так далее, пока не закончится весь стек патчей, но скорее всего так просто он не закончится. Задача — обновляя патчи, устранить конфликты. После принудительного применения (quilt push -f) следует вручную просмотреть все конфликтные места и исправить их нужным образом. Каждый патч отслеживает только некоторое число файлов (quilt files), но если отредактирован файл не из списка, то его нужно добавить (quilt add). После того как все исправлено, нужно обновить текущий патч: quilt refresh (это такой аналог commit, который исправляет текущий наложенный патч, основываясь на рабочей директории и предыдущей спрятанной копии)
>quilt refresh Патч patches/libdc1394-v4l-2.6.38.patch обновлён
Tue, Jan 22, 2013
Matwey Kornilov
posted at
13:33
udev и camsource
(Пере)запускалка camsource (программы для показывания картинок с веб-камер) с помощью udev:
Запускается на старте (когда udev обнаруживается usb-устройства), и перезапускается при их перетыкании (или перетыкивании).
Можно было бы сделать более красиво, т.е. использовать события "add" и "remove" и переменную DEVICE. Однако этому мешает, во-первых, использование нескольких источников в моей конфигурации (и camsource -k выключил бы сразу все), во-вторых какой-то встроенный глюк в самой программе. Дело в том, что запускаясь, процесс почему-то уходит в состояние зомби, и в /proc/NNNNN/fd оказывается пустота. А при использовании параметра [device] код ищет процесс именно по файловым дескрипторам. Иначе говоря, этот параметр вообще не работает.
Применив фантазию к udev, можно например включать трансляцию видео-потока. Что даже удобнее, чем вписывание не комплектуемых init.d-скриптам запуска camsource, ffserver и т.п. во всякие странные места типа /etc/init.d/boot.local.
SUBSYSTEM=="video4linux", ACTION=="add", RUN+="/usr/bin/camsource -r /etc/camsource.conf"
Запускается на старте (когда udev обнаруживается usb-устройства), и перезапускается при их перетыкании (или перетыкивании).
Можно было бы сделать более красиво, т.е. использовать события "add" и "remove" и переменную DEVICE. Однако этому мешает, во-первых, использование нескольких источников в моей конфигурации (и camsource -k выключил бы сразу все), во-вторых какой-то встроенный глюк в самой программе. Дело в том, что запускаясь, процесс почему-то уходит в состояние зомби, и в /proc/NNNNN/fd оказывается пустота. А при использовании параметра [device] код ищет процесс именно по файловым дескрипторам. Иначе говоря, этот параметр вообще не работает.
Применив фантазию к udev, можно например включать трансляцию видео-потока. Что даже удобнее, чем вписывание не комплектуемых init.d-скриптам запуска camsource, ffserver и т.п. во всякие странные места типа /etc/init.d/boot.local.
Sat, Jan 19, 2013
Matwey Kornilov
posted at
11:55
OBS tar_scm: versionformat
Сервис для OBS под названием tar_scm позволяет автоматически создавать архивы из указанных репозиториев систем контроля версий исходных кодов. Естественно, имеет много параметров, описание которых не так просто найти. На головном web-интерфейсе взаимодействие с сервисами куда-то с недавних пор вообще пропало, там хоть какие-то подсказки содержались.
versionformat — один из самых любопытных параметров, позволяющих хоть как-то оформить название архива, для последующего действия сервиса set_version.
versionformat — один из самых любопытных параметров, позволяющих хоть как-то оформить название архива, для последующего действия сервиса set_version.
- Для git в это поле можно указать:
- @PARENT_TAG@ — bash любезно заменит на ближайший тег
- поля из --pretty=format для последнего по времени коммита — полный список внизу, какой-то смысл в данной ситуации имеют %ct %cd %h (UNIX таймштамп, дата YYYYMMDD, короткий хэш коммита), причем дефисы будут любезно удалены по дороге sed'ом (даты будут получается в духе 20121221).
- Для mercurial (hg):
- поля из --template для последнего по времени коммита — полный список внизу. Огромное богатство для фантазии, есть встроенная опция для latesttag. Во время написания этого текста, не было способа выдать дату в виде YYYYMMDD, без дефисов. Сейчас все дефисы удаляются sed'ом, однако последняя версия tar_scm может быть еще не загружена на головной сервис.
- svn понимает только %r — номер ревизии
Sun, Dec 16, 2012
Matwey Kornilov
posted at
10:52
pwdutils RIP
Широко анонсированный конец света начал потихоньку наступать. Спустя пару месяцев с момента написания моего предыдущего поста shadow-utils vs. pwdutils, основной разработчик pwdutils Торсен Кукук (Thorsten Kukuk) взял и «тихо и незаметно» выпилил pwdutils из следующего релиза openSUSE 12.3 в пользу shadow (Вероятно восклицая в этот момент «Стой и не шевелись! Я тебя породил, я тебя и убью!»).
Репортаж с места события:
Возрадуемся же необходимости оборачивать свои spec-файлы очередными несвежими условными операторами, впрочем я уже давно и так это делаю:
p.s. Неужели pam_unix2.so будет следующей жертвой унификации?
Репортаж с места события:
- https://features.opensuse.org/314473
- README.changes-pwdutils (самый полный список различий смотрите тут)
- http://lists.opensuse.org/archive/opensuse-packaging/2012-11/msg00096.html — первые поломки не заставили себя долго ждать
Возрадуемся же необходимости оборачивать свои spec-файлы очередными несвежими условными операторами, впрочем я уже давно и так это делаю:
%if 0%{?fedora} || 0%{?rhel_version} || 0%{?centos_version} %define usermod_A /usr/sbin/usermod -a -G %else %define usermod_A /usr/sbin/usermod -A %endif
p.s. Неужели pam_unix2.so будет следующей жертвой унификации?
Sat, Oct 20, 2012
Matwey Kornilov
posted at
09:27
OBS submit request top
There was a discussion on submit requests. Adrian Schröter and Jos Poortvliet suggested to use OBS api to generate some kind of reports on pending times. Here is a test (I will publish this python script on github or something like that). I've filtered out all "home:" projects and built following table. To my surprise, there are only a little stalled requests.
Generated at: 2013-04-13 05:27:41.044818
Sat, Oct 06, 2012
Matwey Kornilov
posted at
14:30
shadow-utils vs. pwdutils
Существуют два пакета утилит: shadow-utils и pwdutils (применяется в SUSE). Служат они для одной цели — редактирования групп и пользователей, но при этом значения набора параметров отличаются. Среди шестерки утилит user{add,mod,del} и group{add,mod,del}, к счастью, наблюдается некоторая систематика.
В shadow-utils следующие параметры имеют всегда одинаковое значение (в pwdutils отсутствуют, если явно не указано обратное):
При этом ключи pwdutils другое (в shadow-utils отсутствуют, если явно не указано обратное):
Кроме этого, для каждой команды присутствуют индивидуальные особенности. Их условно можно поделить на три группы: ключ означает разные вещи; ключ отсутствует в одной из реализаций; ключ присутствует, значение совпадает, но это не отражено в документации.
С проблемами первой условной группы можно было бы бороться используя явные длинные названия. Это делает скрипт более длинным, но и более явным. Однако, для -e длинные варианты отличаются: --expiredate и --expire.
В shadow-utils следующие параметры имеют всегда одинаковое значение (в pwdutils отсутствуют, если явно не указано обратное):
Ключ | Значение |
---|---|
-D | изменяет значения по умолчанию |
-K | key=value для значений по умолчанию |
-R | запускать в chroot |
-Z | пользователь SELinux |
При этом ключи pwdutils другое (в shadow-utils отсутствуют, если явно не указано обратное):
Ключ | Значение |
---|---|
-D | DN для LDAP |
-P | путь к /etc/passwd и /etc/shadow |
Кроме этого, для каждой команды присутствуют индивидуальные особенности. Их условно можно поделить на три группы: ключ означает разные вещи; ключ отсутствует в одной из реализаций; ключ присутствует, значение совпадает, но это не отражено в документации.
С проблемами первой условной группы можно было бы бороться используя явные длинные названия. Это делает скрипт более длинным, но и более явным. Однако, для -e длинные варианты отличаются: --expiredate и --expire.
useradd
Ключ | Shadow | Pwd |
---|---|---|
-M | не создавать /home | нет |
-N | не создавать группу пользователю | нет |
-U | создать пользователю одноименную группу | маска umask для домашней директории |
-b | базовый каталог, вместо /home | нет |
-l | не добавлять в lastlog | нет |
usermod
Ключ | Shadow | Pwd |
---|---|---|
-A | нет | добавить в группу (аналог -a -G) |
-R | запускать в chroot | удалить из группы |
-a | (вместе с -G) добавить в группу | недокументированный |
groupadd
Ключ | Shadow | Pwd |
---|---|---|
-f | не ругаться, если группа уже есть | недокументированный |
groupmod
Ключ | Shadow | Pwd |
---|---|---|
-A | нет | добавить пользователя в группу |
-R | запускать в chroot | удалить пользователя из группы |
-n | переименовать | недокументированный |
Tue, Jun 12, 2012
Matwey Kornilov
posted at
14:37
Mercurial
Минимальная инфраструктура для работы с распределенной системой контроля версий Mercurial настраивается следующим образом.
Во-первых, нужно где-то разместить репозитории. Поскольку никаких других рекомендаций не поступало, по аналогии с cvs и svn будем класть все в /srv/hg/repos. Во-вторых, нужно обеспечить теперь доступ разным пользователям, которые счастливо существуют на компьютере и что-то там делают. Основная инструкция тут: http://mercurial.selenic.com/wiki/MultipleCommitters. Краткая инструкция: по аналогии с cvs и svn, создаем системную группу hg, системного пользователя hg, добавляем всех пользователей в группу hg.
Схема создания нового репозитория выглядит следующим образом:
Mercurial >1.0 сам, о чудо, разбирается с правами доступа и делает так, чтобы все кому надо могли туда писать. Вообще говоря, данный подход (пулить всем вместе в один репозиторий) полностью противоречит идеологии hg.
В-третьих, никак не обойтись без веб-интерфейса. В /usr/share/doc/packages/mercurial живет пример под названием hgweb.cgi. Кладем его в /srv/hg/bin/hgweb.fcgi и меняем примерно следующим образом (чтобы через FastCGI работал):
Конфигурация для lighttpd (обычно кладется куда-нибудь в /etc/lighttpd/vhosts.d/hgweb.conf):
Что писать в /srv/hg/config подсказывают в hg help hgweb:
Последняя строчка для того, чтобы пользователям было не обидно, там они хранят свои личные репозитории. Вот только . Поля "Description" и "Contact" настраиваются в .hg/hgrc персонально для каждого репозитория. Кроме того, теперь через http возможно анонимное клонирование.
Во-первых, нужно где-то разместить репозитории. Поскольку никаких других рекомендаций не поступало, по аналогии с cvs и svn будем класть все в /srv/hg/repos. Во-вторых, нужно обеспечить теперь доступ разным пользователям, которые счастливо существуют на компьютере и что-то там делают. Основная инструкция тут: http://mercurial.selenic.com/wiki/MultipleCommitters. Краткая инструкция: по аналогии с cvs и svn, создаем системную группу hg, системного пользователя hg, добавляем всех пользователей в группу hg.
Схема создания нового репозитория выглядит следующим образом:
cd repos/ mkdir test chown -R hg:hg test cd test/ hg init chown -R hg:hg .hg chmod -R g+w .hg chmod g+s .hg .hg/store .hg/store/data
Mercurial >1.0 сам, о чудо, разбирается с правами доступа и делает так, чтобы все кому надо могли туда писать. Вообще говоря, данный подход (пулить всем вместе в один репозиторий) полностью противоречит идеологии hg.
В-третьих, никак не обойтись без веб-интерфейса. В /usr/share/doc/packages/mercurial живет пример под названием hgweb.cgi. Кладем его в /srv/hg/bin/hgweb.fcgi и меняем примерно следующим образом (чтобы через FastCGI работал):
#!/usr/bin/python config = "/srv/hg/config" from mercurial import demandimport; demandimport.enable() from mercurial.hgweb import hgweb, wsgicgi from flup.server import fcgi application = hgweb(config) fcgi.WSGIServer(application).run()
Конфигурация для lighttpd (обычно кладется куда-нибудь в /etc/lighttpd/vhosts.d/hgweb.conf):
fastcgi.server += ( "/hg" => (( "bin-path" => "/srv/hg/bin/hgweb.fcgi", "socket" => socket_dir + "/hgweb.sock", "max-procs" => 1, "check-local" => "disable", "fix-root-scriptname" => "enable", )) )
Что писать в /srv/hg/config подсказывают в hg help hgweb:
[paths] / = /srv/hg/repos/* /home/user = /home/user/hg/**
Последняя строчка для того, чтобы пользователям было не обидно, там они хранят свои личные репозитории. Вот только . Поля "Description" и "Contact" настраиваются в .hg/hgrc персонально для каждого репозитория. Кроме того, теперь через http возможно анонимное клонирование.
Matwey Kornilov
posted at
10:59
В openSUSE перерабатывают страницу software.
В openSUSE перерабатывают страницу software.opensuse.org и придумали полезную вещь, встраиваемый в веб-страницы виджет с информацией о пакетах; инструкция здесь.
Выглядит примерно так:
Выглядит примерно так: