Back to Home

Automate mounting samba partitions on Mac OS

bash-scripting · samba · mac os x · beginner

Automate mounting samba partitions on Mac OS

On the third day, I raised the server for file cleaning, backups, torrents and other household needs. There samba deployed with a lot of ball, in particular with personal data and a place for laptop backups through TimeMachime. Immediately I did not like the constant manual mounting of balls and the image for backup. Below I want to share scripts with the community to automate this process.

Reasons for inconvenience


Each time to connect to the samba, you need to poke the mouse fairly: Finder -> Connect to the server -> enter the server name (-> the first time they will also ask for the password) -> select the folders that you need to connect -> Ok. Then, if you want to backup to a directory mounted on samba, you also have to create a .sparsebundle image and mount it as well. All this, perhaps, is not very annoying if you do it every couple of weeks on a stationary PC, which is constantly on the same network and does not turn off the same way as the server. But when it is necessary to do this after each switching on / waking up the laptop, it doesn’t go into any gates. Plus, it turned out that if you didn’t unmount the partitions and change the network (say, visit a neighbor), the system would hang pretty much after getting out of sleep, because it couldn’t find a server with balls, and, in rare cases, also happens in kernel panic. All this greatly overshadowed the joy of raising the server and the dream that I won’t even remember about backups until I needed them (pah pah pah). It was decided that the process should be automated.

At first


In the priests, methods for mounting samba were googled and a small script was born from a couple of identical commands of the following type:
mkdir -p /mount/point

It was also found how to make an image attachment for TimeMachine:
hdiutil attach -mountpoint /mount/point /path/to/image.sparsebundle/
hdutil turned out to be more intelligent and didn’t work on creating folders.
The first version of the script was ready.

Security


It was very annoying to specify the password explicitly when mounting. After reading the mans for mount_smbfs, I learned about nsmb.conf . But the idea was also not very well liked, since anyway the password is stored somewhere in the file in the clear. I immediately remembered that through the GUI the password was asked once, and then pulled out of the keychain. I wanted to use it. It turned out automatically, as if I took nsmb.conf and added the -N switch to mount_smbfs , the password will not be substituted (a miracle did not happen). First you have to get it through security and then transfer it to the right place. For these purposes, the function was googled and redone to fit your needs:
get_inet_pwd () {
 security find-internet-password -gwl $1
}

After that, the explicit password was replaced by:
mount -t smbfs //user:"$(get_inet_pwd server-pc)"@server-pc/shara_name /mount/point

Paranoia retreated, but curiosity and perfectionism remained, so the matter continued.

Enhancements and Expansion


I wanted to make one script to mount everything all at once, but I didn’t have to repeat the code so that it was extensible many times, plus to see that it was already mounted in the system and did not try to mount it a second time. No sooner said than done. I will describe everything in order.

To determine the mounting, at the first stage, the most "clumsy" method was used
if [ ! -d /mount/point/ ]; then
  mkdir -p /mount/point
  mount …
fi

But immediately it became clear that the directory might be present, but not a mount point for anything. Therefore, I made a function to check:
is_volume_mounted() {
  volume_name=$1
  mount | awk -v volume_name=$volume_name '$3 == volume_name {print $3}'
}
The method is also not ideal, but much better than just checking for a directory.

The same thing was done to check the backup image:
is_image_attached() {
  img_path=$1
  df -Hl | awk -v img_path=$img_path '$9 == img_path {print $9}'
}

After some thought and reading the forums, the method became bloated and immediately began to check whether the image was mounted and, if not, mount it.
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
}

Next, we needed a function to perform checks and automation on mounting any number of ball from the server. This is how it turned out:
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
}

An attentive reader will notice that firstly: you can pass the server name in the parameters to the function, rather than hardcode it, and secondly: the unknown function is_samba_exist is found in the script .

I answer in order: the third parameter for the function was laziness, because so far no second server with samba has been planned; The is_samba_exist function has the following form:
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}'
}
It is easy to guess that the function checks for the presence of balls with the specified name in the current network.

Thus, the main part of the script became simple, understandable and extensible:
try_mount_server_samba "shara_name" "/mount/point"
try_attach_fs_image "/path/to/image.sparsebundle" "/mount/point"

Lastly, in the image and likeness of the above script, another one was created, but already for unmounting everything at once:
#!/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"

That's all. Further scripts were carried away to their brothers in ~ / .script . Got short aliases in .bash_profile and began to help me with samba.

Prospects


In the future, when my hands reach, I want to make friends scripts with SleepWatcher , so that they are executed after leaving sleep and before going into it. That is, so that you don’t have to do anything with your hands and automation becomes complete.

PS thanks to comrade helios for the -w switch for security .

Read Next