[Из песочницы] Автоматизация монтирования samba-разделов в Mac OS
Третьего дня поднял сервер для файлопомойки, бэкапов, торрентов и прочих домашних нужд. Там развернулась samba с множеством шар, в частности с личнми данными и местом под бэкапы ноутбука через TimeMachime. Сразу же не понравилось постоянное ручное монтирование шары и образа для бэкапа. Ниже хочу поделиться с сообществом скриптами по автоматизации этого процесса.Причины неудобствКаждый раз для подключения к самбе надо изрядно потыкать мышкой: Finder → Подключение к серверу → ввод имени сервера (→ первый раз ещё и пароль спросят) → выбор папок, которые нужно подключить → Ok. Потом, если захочется делать бэкап в примонтированную по самбе директорию, прийдётся ещё и образ .sparsebundle создавать, и монтировать ещё и его. Всё это, возможно, и не сильно напрягает, если делать раз в пару недель на стационарном ПК, который постоянно находится в одной и той же сети и не выключается так же, как и сервер. Но когда это надо делать после каждого включения/пробуждения ноутбука — это ни в какие ворота не лезет. Плюс к этому выяснилось, что если не отмонтировать разделы и сменить сеть (скажем прийти к соседу в гости), то система изрядно виснет после выхода из сна, ибо не находит сервер с шарами, а, в редких случаях, ещё и в kernel panic случается. Всё это сильно омрачило радость поднятия сервера и мечты о том что больше я даже вспоминать не буду о бэкапах, пока они мне не понадобятся (тьфу тьфу тьфу). Было решено, что процесс нужно автоматизировать.На первых порах В попыхах были нагуглены способы монтирования самбы и тут же родился маленький скрипт из парочки идентичных команд следующего вида: mkdir -p /mount/point Так же было найдено как сделать аттач образа для TimeMachine: hdiutil attach -mountpoint /mount/point /path/to/image.sparsebundle/ hdutil оказался более смышлёным и создание папок не потреловал.Первая версия скрипта была готова.Безопасность Очень напрягало указание пароля в явном виде при монтировании. Почитав ман для mount_smbfs узнал про nsmb.conf. Но идея так же не шибко понравилась, так как всё равно пароль хранится где-то в файле в открытом виде. Тут же вспомнил, что через GUI пароль спрашивают единожды, а далее вытаскивают из keychain. Захотелось использовать её. Оказалось автоматически, как если бы взял nsmb.conf и дописал ключик -N к mount_smbfs, пароль подставляться не будет (чуда не произошло). Прийдёся его сначала получать через security и затем передавать в нужное место. Для сих целей была нагуглена и переделана под свои нужды функция: get_inet_pwd () { security 2>&1 >/dev/null find-internet-password -gl $1 \ |ruby -e 'print $1 if STDIN.gets =~ /^password:»(.*)»$/' } После этого явное указание пароля было заменено на: mount -t smbfs //user:»$(get_inet_pwd server-pc)»@server-pc/shara_name /mount/point Паранойя отступила, но любознательность и перфекционизм остались, поэтому дело продолжилось.Улучшения и расширение Захотелось сделать один скрипт для монтирование всего и сразу, да так сделать, чтобы он расширяемый было и повторять код много раз не пришлось, плюс чтобы смотрел что уже в системе примонтировано и второй раз монтировать не пытался. Сказано — сделано. Опишу всё по-порядку.Для определения примонтированости, на первом этапе, был использован самый «топорный» метод
if [ ! -d /mount/point/ ]; then mkdir -p /mount/point mount… fi Но сразу же стало понятно, что директория может и присутствовать, но не являться точкой монтирования для чего-либо. Поэтому сделал функцию для проверки: is_volume_mounted () { volume_name=$1 mount | awk -v volume_name=$volume_name '$3 == volume_name {print $3}' } Метод тоже не идеален, но уже гораздо лучше, нежели простая проверка наличия директории.То же самое было сделано и для проверки образа бэкапа:
is_image_attached () { img_path=$1 df -Hl | awk -v img_path=$img_path '$9 == img_path {print $9}' } После некоторых раздумий и чтения форумов метод раздулся и стал сразу проверять примонтирован ли образ, и, если нет, то монтировать его. try_attach_fs_image () { img_path=$1 mnt_pnt_path=$2 # check existance of image file if [ -d $img_path ]; then # check if image alredy attached in system if [[ $(df -Hl | awk -v img_path=$img_path '$9 == img_path {print $9}') != » ]]; then echo image $img_path alredy attached else hdiutil attach -mountpoint $mnt_pnt_path $img_path fi fi } Далее нужна была функция для выполнения проверок и автоматизации по монтированию любого количества шар с сервера. Вот какой она получилась: try_mount_server_samba () { smb_vol_name=$1 mnt_pnt_path=$2 # check if samba share exist in network if [[ $(is_samba_exist $smb_vol_name) != » ]]; then # check if samba alredy mounted if [[ $(is_volume_mounted $mnt_pnt_path) != » ]]; then # show message about that echo volume $mnt_pnt_path alredy mounted else # check if moint point directory not exist if [ ! -d $mnt_pnt_path ]; then mkdir -p $mnt_pnt_path fi # otherwise — mount volume mount -t smbfs //user:»$(get_inet_pwd server-pc)»@server-pc/$smb_vol_name $mnt_pnt_path fi fi } Внимательный читатель заметит, что во-первых: можно и имя сервера передавать в параметрах к функции, а не хардкодить его, а во-вторых: в скрипте встречается неизвестная функция is_samba_exist.Отвечаю по-порядку: 3-й параметр для функции было делать лень, ибо пока второго сервра с самбой не планируется; функция is_samba_exist имеет следующий вид:
is_samba_exist () { smb_vol_name=$1 smbutil view //user:»$(get_inet_pwd server-pc)»@server-pc/ | awk -v smb_vol_name=$smb_vol_name '$1 == smb_vol_name {print $1}' } Несложно догадаться, что функция проверяет наличие шары с указанным именем в текущей сети.Таким образом основная часть скрипта стала простой, понятной и расширяемой:
try_mount_server_samba «shara_name» »/mount/point» try_attach_fs_image »/path/to/image.sparsebundle» »/mount/point» На последок, по образу и подобию вышеописанного скрипта, был создан ещё один, но уже для отмонтирования сразу всего: #!/bin/sh
# unmount volume if it mounted # syntax: umount_volume »/path/to/volume» umount_volume () { vol_path=$1 if [[ $(mount | awk -v vol_path=$vol_path '$3 == vol_path {print $3}') != » ]]; then umount $vol_path echo $vol_path is unmounted fi }
# detach filesystem image if it attached # syntax: detach_fs_image »/path/to/fs/image» detach_fs_image () { img_path=$1 if [[ $(df -Hl | awk -v img_path=$img_path '$9 == img_path {print $9}') != » ]]; then hdiutil detach $img_path echo $img_path is detched fi }
# main part
# umnount data volume umount_volume »/data/mount/point»
# firstly detach image from backup volume detach_fs_image »/backup/image/mount/point» # secondary unmount backup volume umount_volume »/backup/volume/mount/point» Вот и всё. Дальше скрипты были унесены к своим собратьям в ~/.script. Получили короткие алиасы в .bash_profile и стали помогать мне с самбой.Перспективы В будущем, когда дойдут руки, хочется подружить скрипты со SleepWatcher, дабы выполнялись они после выхода из сна и перед уходом в него же. То есть, чтобы совсем ничего не надо было делать руками и автоматизация стала полной.