最終形
問題
Mac覚書 TimeMachineでNASを使用する方法
NAS上にTimeMachineファイルを置いてTimeMachineを使っても、起動時
、Sleep後
はsparsebundleファイルをマウントし直さないとTimeMachineが機能しない。
解決策
samba経由でnasのフォルダをマウントして、samba上のsparsebundleファイルを自動でマウントするようにする。
- rubyで書きたい
- plistで自動起動させたい
方法
まず、samba経由で目的のNASフォルダをマウントする
#マウント先フォルダを作って
mkdir /Volumes/your_mount_name
#sambaフォルダをマウント nasにログインできる「guest:」か「login:pass」で
mount_smbfs //guest:@your_nas_name/your_path_name /Volumes/your_mount_name
マウントしたフォルダ内にあるsparsebundleファイルをさらにマウントする
hdiutil attach -mountpoint /Volumes/your_timemachine_mount_name /Volumes/your_mount_name/your_timemachine.sparsebundle
これをrubyにまとめて引数で指定できるようしたうえで、さらにosxのnotification
で表示できるようにterminal-notifier
をインストール
brew install terminal-notifier
まとめたものがこれ
rubyファイル
# timemachine.drive.rb
require "pathname"
require "shellwords"
class AutoTimeMachineDrive
class << self
def mount!
new.mount_timemachine_drive
rescue => ex
notify(ex.message)
end
def notify(message)
options = {
group: self.to_s,
title: self.to_s,
message: message,
sound: :default
}
system "/usr/local/bin/terminal-notifier #{option_line options}"
end
def option_line(*options)
options.collect do |element|
case element
when Hash
element.collect{|k, v| "-#{k} #{Shellwords.escape v}"}.join " "
when String, Pathname
element.to_s
end
end.join " "
end
end
def initialize
@smb_url, @smb_mount_name,
@time_machine_mount_name, @time_machine_sparsebundle_file_path = ARGV
end
def mount_timemachine_drive
return if tm_mount_point.exist?
ensure_smb_mount_point do
ensure_tm_mount_point_is_missing do
mount_timemachine_sparsebundle_file
self.class.notify("#{time_machine_mount_name} mounted.") if tm_mount_point.exist?
end
end
end
private
attr_reader :smb_url, :smb_mount_name,
:time_machine_mount_name, :time_machine_sparsebundle_file_path
def smb_mount_point
Pathname "/Volumes/#{smb_mount_name}"
end
def tm_mount_point
Pathname "/Volumes/#{time_machine_mount_name}"
end
def ensure_smb_mount_point
prepare_smb_mount_point do
mount_samba
yield
end
end
def ensure_tm_mount_point_is_missing
yield unless tm_mount_point.exist?
end
def prepare_smb_mount_point
if smb_mount_point.exist?
if [smb_mount_point_not_network_drive?, smb_mount_point_not_empty?].all?
return self.class.notify "unempty smb_mount_point (#{smb_mount_point}) exists. make sure this directory is removed before running."
end
else
smb_mount_point.mkdir
end
yield
end
def smb_mount_point_not_network_drive?
`mount`.lines.select{|line| line.include? smb_mount_point.to_s }.count == 0
end
def smb_mount_point_is_network_drive?
not smb_mount_point_not_network_drive?
end
def smb_mount_point_not_empty?
smb_mount_point.children.count > 0
end
def mount_samba
return if smb_mount_point_is_network_drive?
system "mount_smbfs #{self.class.option_line(smb_url, smb_mount_point)}"
end
def mount_timemachine_sparsebundle_file
system "hdiutil attach #{self.class.option_line(
{mountpoint: tm_mount_point},
time_machine_sparsebundle_file_path
)}"
end
end
AutoTimeMachineDrive.mount!
このファイルをtimemachine.drive.rb
などとして~/bin
などに入れて、次にplistを作る
plistファイル
<!-- local.timemachine.drive.plist -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>local.timemachine.drive</string>
<key>ProgramArguments</key>
<array>
<string>ruby</string>
<!--rbファイルのフルパス-->
<string>/Users/your_name/bin/timemachine.drive.rb</string>
<!--ログインできるNASのURL-->
<string>//guest:@your_nas_name/your_path_name</string>
<!--sambaフォルダのマウント名 /Volumes配下に自動マウント-->
<string>your_mount_name</string>
<!--sparsebundleマウント時の表示ドライブ名-->
<string>your_timemachine_mount_name</string>
<!--samba経由で参照できるsparsebundleフルパス(/Volumes配下経由)-->
<string>/Volumes/your_mount_name/your_timemachine.sparsebundle</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>StartInterval</key>
<integer>60</integer>
</dict>
</plist>
launchctlのロード
local.timemachine.drive.plist
などとしたこのplistを~/Library/LaunchAgents/
に置いて
launchctl load ~/Library/LaunchAgents/local.timemachine.drive.plist
このコマンド一発で自動にTimeMachineドライブをマウントします。