Недавно к нам обратился один заказчик с маленькой проблемой: на его SunRay-сервере, установленном на сервере SPARC Enterprise T5120 не работали флешки с файловыми системами NTFS и exFAT. Вопрос с переносом все x86-железку с Linux на борту не рассматривался, так что пришлось импровизировать.
prepare
Как известно, в Linux существует подсистема FUSE (Filesystem in USErspace), позволяющая писать драйвера файловых систем как обычные пользовательские программы, которые просто форкаются от mount. При разработке OpenSolaris она была худо-бедно портирована (на Solaris 10 из-за некоторых изменений в VFS не собирается), а в Solaris 11 превратилась в UVFS, сильно урезанный вариант FUSE, из-за чего не позволяющий использовать NTFS и exFAT. Поэтому пришлось вытаскивать исходники с hg.opensolaris.org, и собирать руками FUSE, что как оказалось не очень сложно. Единственная проблема, возникшая состояла в том, что FUSE использует символ ',' для разделения опций файловой системы, тогда как в Solaris имена устройств могут содержать запятые, и поэтому следующая строка:
...,fsname=/tmp/SUNWut/units/IEEE802.002128f8888b/devices/usb@1/hub@1/USB2.0,USB_FLASH_DRIVE@1:1
приведет к тому, что имя устройства окажется /tmp/SUNWut/units/IEEE802.002128f8888b/devices/usb@1/hub@1/USB2.0
и дезориентирует SunRay Software. Я по-началу думал, что проблему может решить экранирование запятых. Однако, как оказалось SunRay Software требует вообще символических ссылок вида /tmp/SUNWut/units/IEEE802.002128f8888b/dev/dsk/disk1s2
.
Сказано - сделано:
@@ -523,7 +563,7 @@ char *parse_mount_options(ntfs_fuse_context_t *ctx,
if (ntfs_strappend(&ret, "fsname="))
goto err_exit;
- if (ntfs_strappend(&ret, popts->device))
+ if (ntfs_strappend_escaped(&ret, popts->arg_device))
goto err_exit;
if (permissions && !acl)
ctx->secure_flags |= (1 << SECURITY_DEFAULT);
Еще одна проблема состоит в том, что Solaris на SPARC не умеет разделы и MBR-метку - поддерживается только типичная для SPARC VTOC. К счастью, и в ntfs-3g и в fuse-exfat предусмотрены обертки над функциями pread, pwrite и lseek и не составляет труда в этих функциях-обертках прибавлять смещение, соответствующее разделу, а при монтировании устройства эти самые разделы опеределять (так собственно делает драйвер файловой системы FAT pcfs, правда он через специальный синтаксис указания раздела в имени устройства). Однако если кто-то придет с внешним жестким диском с разделами NTFS и exFAT, смонтируется только одна ФС.
configure && make
Теперь можно собирать исходники. Для этого нам потребуется:
-
Solaris Studio 12.3 и пакет developer/build/onbld, чтобы собрать FUSE
-
GCC (в Solaris он живет в пакете developer/gcc-45) , чтобы собрать ntfs-3g и fuse-exfat
-
Систему сборки SCons для fuse-exfat
Сборка и установка пакетов FUSE выглядит так:
# export PATH=$PATH:/opt/solarisstudio12.3/bin:/opt/onbld/bin/sparc/
# dmake
# dmake install
# dmake pkg
# pkgrm <pkg-name>
# pkgadd -d packages/ <pkg-name>
ntfs-3g собирается следующим образом:
# ./configure --with-fuse=external --prefix=/opt/ntfs/
# make
# make install
Еще проще (если не считать время на установку SCons
) собрать fuse-exfat:
# scons install
patch && fix
Для того, чтобы идентифицировать файловую систему Solaris использует утилиту fstyp и набор плагинов с именами fstyp.so.1
, лежащими в директориях /usr/lib/fs/<имя ФС>
. Можно конечно, положить в указанную директорию свой fstyp,
и тогда именно он будет вызываться, а его например сделать скриптом-оберткой над ntfs-3g.probe
. Но я узнал про этот метод уже после того, как реализовал указанные плагины - они расположены в дереве исходников в директории tools/ и собираются так:
Для ntfs-3g:
# gcc -o fstyp.so.1 fstyp.c -fpic -lntfs-3g -shared
Для fuse-exfat:
# gcc -o fstyp.so.1 fstyp.c -D_FILE_OFFSET_BITS=64 -O2 -fPIC -lexfat -shared
Кроме этого, надо создать жесткие ссылки на утилиту fstyp в директориях /usr/lib/fs/ntfs
и /usr/lib/fs/exfat
и добавить setuid-бит на утилиты /bin/ntfs-3g
, /sbin/mount.exfat-fuse
и /usr/lib/fs/fuse/fusermount.bin
Теперь можно полезть своими руками в недра SunRay Software, для того, чтобы рассказать ему про эти файловые системы. Во-первых надо изменить в файлах /opt/SUNWut/bin/utdiskadm
и /opt/SUNWut/lib/utprepmount
значения переменных FST_LIST
и FSM_LIST.
А вот утилита /opt/SUNWut/lib/utdomount
является бинарником, так что ее придется обернуть в shell-скрипт - он располагается в файле tools/utdomount.sh
Саму утилиту соответственно мы переименовываем в /opt/SUNWut/lib/utdomount.bin
а на ее место кладем shell-скрипт. В качестве небольшого бонуса он создает для kiosk-пользователей ярлыки на рабочем столе, открывающие/отмонтирующие файловую систему.
Последний фикс который мне пришлось внести связан с интересной логикой разработчика fuse-exfat. На любой внутренний сбой он вместо того, чтобы вернуть EIO ядровому драйверу fuse, он вызывает exfat_bug()
, а она в свою очередь abort()
, от чего процесс, отвечающий за файловую систему аварийно завершается. Solaris от такой радости падает в панику, унося за собой всю систему. Так что пришлось потратить день на перелопачивание кода fuse-exfat 
wget && tar x
Свежий ntfs-3g лежит тут: http://www.tuxera.com/community/ntfs-3g-download/
Драйвер fuse-exfat тут: http://code.google.com/p/exfat/downloads/list
Все исходники есть в GitHub-репозитории: https://github.com/myaut/solaris-sparc-fuse
Ленивые могут скачать бинарную сборку для T5120/Solaris 11.1:
fuse-exfat-ntfs-1.0.1.tar