Compare commits
No commits in common. "0.8" and "master" have entirely different histories.
555
HOWTO.htm
555
HOWTO.htm
|
|
@ -1,555 +0,0 @@
|
||||||
<style>
|
|
||||||
body { margin-left: 16px;
|
|
||||||
margin-right: 16px;
|
|
||||||
font-size: 12px;
|
|
||||||
font-family: georgia;
|
|
||||||
}
|
|
||||||
tt { color: #444444; }
|
|
||||||
pre { color: #444444;
|
|
||||||
background: #eeeeee;
|
|
||||||
border-left: solid 5px #2222dd;
|
|
||||||
padding: 1px 1px 1px 7px; }
|
|
||||||
pre b, tt b { color: #2222dd; }
|
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<h1>FreeBSD ZFS Madness</h1>
|
|
||||||
<h3>Slawomir Wojtczak (vermaden)</h3>
|
|
||||||
<h4>2012/04/27</h4>
|
|
||||||
|
|
||||||
<p>Some time ago I found a good, reliable way of using and installing FreeBSD
|
|
||||||
and described it in my <i>Modern FreeBSD Install</i> <b>[1] [2]</b> HOWTO. Now, more
|
|
||||||
then a year later I come back with my experiences about that setup and a
|
|
||||||
proposal of newer and probably better way of doing it.</p>
|
|
||||||
|
|
||||||
<hr style="border: 1px solid lightgray">
|
|
||||||
|
|
||||||
<h3>1. Introduction</h3>
|
|
||||||
|
|
||||||
<p>Same as year ago, I assume that You would want to create fresh installation of
|
|
||||||
FreeBSD using one or more hard disks, but also with (laptops) and without GELI
|
|
||||||
based full disk encryption.</p>
|
|
||||||
|
|
||||||
<p>This guide was written when FreeBSD 9.0 and 8.3 were available and definitely
|
|
||||||
works for 9.0, but I did not try all this on the older 8.3, if You find some
|
|
||||||
issues on 8.3, let me know I will try to address them in this guide.</p>
|
|
||||||
|
|
||||||
<p>Earlier, I was not that confident about booting from the ZFS pool, but there
|
|
||||||
is some very neat feature that made me think ZFS boot is now mandatory. If You
|
|
||||||
just smiled, You know that I am thinking about <i>Boot Environments</i> feature
|
|
||||||
from Illumos/Solaris systems.</p> In case You are not familiar with the <i>Boot
|
|
||||||
Environments</i> feature, check the <i>Managing Boot Environments with Solaris
|
|
||||||
11 Express</i> PDF white paper <b>[3]</b>. Illumos/Solaris has the
|
|
||||||
<tt>beadm(1M)</tt> <b>[4]</b> utility and while Philipp Wuensche wrote the
|
|
||||||
<tt>manageBE</tt> script as replacement <b>[5]</b>, it uses older style used
|
|
||||||
at times when OpenSolaris (and SUN) were still having a great time.</p>
|
|
||||||
|
|
||||||
<p>I spent last couple of days writing an up-to-date replacement for FreeBSD
|
|
||||||
compatible <tt>beadm</tt> utility, and with some tweaks from today I just made
|
|
||||||
it available at <i>SourceForge</i> <b>[6]</b> if You wish to test it. Currently its
|
|
||||||
about 200 lines long, si it should be pretty simple to take a look at it. I
|
|
||||||
tried to make it as compatible as possible with the 'upstream' version, along
|
|
||||||
with some small improvements, it currently supports basic functions like list,
|
|
||||||
create, destroy and activate.</p>
|
|
||||||
|
|
||||||
<pre># <b>beadm</b>
|
|
||||||
usage:
|
|
||||||
beadm subcommand cmd_options
|
|
||||||
|
|
||||||
subcommands:
|
|
||||||
|
|
||||||
beadm activate beName
|
|
||||||
beadm create [-e nonActiveBe | beName@snapshot] beName
|
|
||||||
beadm create beName@snapshot
|
|
||||||
beadm destroy beName
|
|
||||||
beadm destroy beName@snapshot
|
|
||||||
beadm list</pre>
|
|
||||||
|
|
||||||
<p>There are several subtle differences between mine implementation and
|
|
||||||
Philipp's one, he defines and then relies upon ZFS property called
|
|
||||||
<tt>freebsd:boot-environment=1</tt> for each boot environment, I do not set
|
|
||||||
any other additional ZFS properties. There is already <tt>org.freebsd:swap</tt>
|
|
||||||
property used for SWAP on FreeBSD, so we may use <tt>org.freebsd:be</tt> in the
|
|
||||||
future, but is just a thought, right now its not used. My version also supports
|
|
||||||
activating boot environments received with <tt>zfs recv</tt> command from other
|
|
||||||
systems (it just updates appreciate <tt>/boot/zfs/zpool.cache</tt> file).</p>
|
|
||||||
My implementation is also style compatible with current Illumos/Solaris
|
|
||||||
<tt>beadm(1M)</tt> which is like the example below.</p>
|
|
||||||
|
|
||||||
<pre># <b>beadm create -e default upgrade-test</b>
|
|
||||||
Created successfully
|
|
||||||
|
|
||||||
# <b>beadm list</b>
|
|
||||||
BE Active Mountpoint Space Policy Created
|
|
||||||
default N / 1.06M static 2012-02-03 15:08
|
|
||||||
upgrade-test R - 560M static 2012-04-24 22:22
|
|
||||||
new - - 8K static 2012-04-24 23:40
|
|
||||||
|
|
||||||
# <b>zfs list -r sys/ROOT</b>
|
|
||||||
NAME USED AVAIL REFER MOUNTPOINT
|
|
||||||
sys/ROOT 562M 8.15G 144K none
|
|
||||||
sys/ROOT/default 1.48M 8.15G 558M legacy
|
|
||||||
sys/ROOT/new 8K 8.15G 558M none
|
|
||||||
sys/ROOT/upgrade-test 560M 8.15G 558M none
|
|
||||||
|
|
||||||
# <b>beadm activate default</b>
|
|
||||||
Activated successfully
|
|
||||||
|
|
||||||
# <b>beadm list</b>
|
|
||||||
BE Active Mountpoint Space Policy Created
|
|
||||||
default NR / 1.06M static 2012-02-03 15:08
|
|
||||||
upgrade-test - - 560M static 2012-04-24 22:22
|
|
||||||
new - - 8K static 2012-04-24 23:40</pre>
|
|
||||||
|
|
||||||
<p>The boot environments are located in the same plase as in Illumos/Solaris, at
|
|
||||||
<tt>pool/ROOT/environment</tt> place.</p>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h3>2. Now You're Thinking with Portals</h3>
|
|
||||||
|
|
||||||
<p>The main purpose of the <i>Boot Environments</i> concept is to make all
|
|
||||||
risky tasks harmless, to provide an easy way back from possible troubles.
|
|
||||||
Think about upgrading the system to newer version, an update of 30+ installed
|
|
||||||
packages to latest versions, testing software or various solutions before
|
|
||||||
taking the final decision, and much more. All these tasks are now harmless
|
|
||||||
thanks to the <i>Boot Environments</i>, but this is just the tip of the
|
|
||||||
iceberg.</p>
|
|
||||||
|
|
||||||
<p>You can now move desired boot environment to other machine, physical or
|
|
||||||
virtual and check how it will behave there, check hardware support on the other
|
|
||||||
hardware for example or make a painless hardware upgrade. You may also clone
|
|
||||||
Your desired boot environment and ... start it as a Jail for some more
|
|
||||||
experiments or move Your old physical server install into FreeBSD Jail because
|
|
||||||
its not that heavily used anymore but it still have to be available.</p>
|
|
||||||
|
|
||||||
<p>Other good example may be just created server on Your laptop inside
|
|
||||||
VirtualBox virtual machine. After you finish the creation process and tests,
|
|
||||||
You may move this boot environment to the real server and put it into
|
|
||||||
production. Or even move it into VMware ESX/vSphere virtual machine and use
|
|
||||||
it there.</p>
|
|
||||||
|
|
||||||
<p>As You see the possibilities with <i>Boot Environments</i> are unlimited.</p>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h3>3. The Install Process</h3>
|
|
||||||
|
|
||||||
<p>I created 3 possible schemas which should cover most demands, choose one
|
|
||||||
and continue to the next step.</p>
|
|
||||||
|
|
||||||
<h4>3.1. Server with Two Disks</h4>
|
|
||||||
|
|
||||||
<p>I assume that this server has 2 disks and we will create ZFS mirror across
|
|
||||||
them, so if any of them will be gone the system will still work as usual.
|
|
||||||
I also assume that these disks are <tt>ada0</tt> and <tt>ada1</tt>. If You
|
|
||||||
have SCSI/SAS drives there, they may be named <tt>da0</tt> and <tt>da1</tt>
|
|
||||||
accordingly. The <b>procedures below will wipe all data on these disks</b>,
|
|
||||||
You have been warned.</p>
|
|
||||||
|
|
||||||
<ol>
|
|
||||||
<li>Boot from the FreeBSD USB/DVD.</li>
|
|
||||||
<li>Select the '<tt>Live CD</tt>' option.</li>
|
|
||||||
<li><tt>login: root</tt></li>
|
|
||||||
<li><tt># sh</tt></li>
|
|
||||||
<li><tt># DISKS="<b>ada0 ada1</b>"</tt></li>
|
|
||||||
<li><tt># for I in ${DISKS}; do<br>
|
|
||||||
> NUMBER=$( echo ${I} | tr -c -d '0-9' )<br>
|
|
||||||
> gpart destroy -F ${I}<br>
|
|
||||||
> gpart create -s GPT ${I}<br>
|
|
||||||
> gpart add -t freebsd-boot -l bootcode${NUMBER} -s 128k ${I}<br>
|
|
||||||
> gpart add -t freebsd-zfs -l sys${NUMBER} ${I}<br>
|
|
||||||
> gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 ${I}<br>
|
|
||||||
> done</tt></li>
|
|
||||||
<li><tt># zpool create -f -o cachefile=/tmp/zpool.cache sys mirror /dev/gpt/sys*</tt></li>
|
|
||||||
<li><tt># zfs set mountpoint=none sys</tt></li>
|
|
||||||
<li><tt># zfs set checksum=fletcher4 sys</tt></li>
|
|
||||||
<li><tt># zfs set atime=off sys</tt></li>
|
|
||||||
<li><tt># zfs create sys/ROOT</tt></li>
|
|
||||||
<li><tt># zfs create -o mountpoint=/mnt sys/ROOT/default</tt></li>
|
|
||||||
<li><tt># zpool set bootfs=sys/ROOT/default sys</tt></li>
|
|
||||||
<li><tt># cd /usr/freebsd-dist/</tt></li>
|
|
||||||
<li><tt># for I in base.txz kernel.txz; do<br>
|
|
||||||
> tar --unlink -xvpJf ${I} -C /mnt<br>
|
|
||||||
> done</tt></li>
|
|
||||||
<li><tt># cp /tmp/zpool.cache /mnt/boot/zfs/</tt></li>
|
|
||||||
<li><tt># cat << EOF >> /mnt/boot/loader.conf<br>
|
|
||||||
> zfs_load=YES<br>
|
|
||||||
> vfs.root.mountfrom="zfs:sys/ROOT/default"<br>
|
|
||||||
> EOF</tt></li>
|
|
||||||
<li><tt># cat << EOF >> /mnt/etc/rc.conf<br>
|
|
||||||
> zfs_enable=YES<br>
|
|
||||||
> EOF</tt></li>
|
|
||||||
<li><tt># :> /mnt/etc/fstab</tt></li>
|
|
||||||
<li><tt># zfs umount -a</tt></li>
|
|
||||||
<li><tt># zfs set mountpoint=legacy sys/ROOT/default</tt></li>
|
|
||||||
<li><tt># reboot</tt></li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<p>After these instructions and reboot we have these GPT partitions available,
|
|
||||||
this example is on a 512MB disk.</p>
|
|
||||||
|
|
||||||
<pre># <b>gpart show</b>
|
|
||||||
=> 34 1048509 ada0 GPT (512M)
|
|
||||||
34 256 1 freebsd-boot (128k)
|
|
||||||
290 1048253 2 freebsd-zfs (511M)
|
|
||||||
|
|
||||||
=> 34 1048509 ada1 GPT (512M)
|
|
||||||
34 256 1 freebsd-boot (128k)
|
|
||||||
290 1048253 2 freebsd-zfs (511M)
|
|
||||||
|
|
||||||
# <b>gpart list | grep label</b>
|
|
||||||
label: bootcode0
|
|
||||||
label: sys0
|
|
||||||
label: bootcode1
|
|
||||||
label: sys1
|
|
||||||
|
|
||||||
# <b>zpool status</b>
|
|
||||||
pool: sys
|
|
||||||
state: ONLINE
|
|
||||||
scan: none requested
|
|
||||||
config:
|
|
||||||
|
|
||||||
NAME STATE READ WRITE CKSUM
|
|
||||||
sys ONLINE 0 0 0
|
|
||||||
mirror-0 ONLINE 0 0 0
|
|
||||||
gpt/sys0 ONLINE 0 0 0
|
|
||||||
gpt/sys1 ONLINE 0 0 0
|
|
||||||
|
|
||||||
errors: No known data errors</pre>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h4>3.2. Server with One Disk</h4>
|
|
||||||
|
|
||||||
<p>If Your server configuration has only one disk, lets assume its
|
|
||||||
<tt>ada0</tt>, then You need different points 5. and 7. to make, use these
|
|
||||||
instead of the ones above.</p>
|
|
||||||
|
|
||||||
<ol start="5">
|
|
||||||
<li><tt># DISKS="<b>ada0</b>"</tt></li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<ol start="7">
|
|
||||||
<li><tt># zpool create -f -o cachefile=/tmp/zpool.cache sys /dev/gpt/sys*</tt></li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<p>All other steps are the same.</p>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h4>3.3. Read Warrior Laptop</h4>
|
|
||||||
|
|
||||||
<p>The procedure is quite diffrent for Laptop because we will use the full disk
|
|
||||||
encryption mechanism provided by GELI and then setup the ZFS pool. Its not
|
|
||||||
currently possible to boot off from the ZFS pool on top of encrypted GELI
|
|
||||||
provider, so we will use setup similar to the <i>Server with ...</i> one but
|
|
||||||
with additional <tt>local</tt> pool for <tt>/home</tt> and <tt>/root</tt>
|
|
||||||
partitions. It will be password based and You will be asked to type-in that
|
|
||||||
password at every boot. The install process is generally the same with new
|
|
||||||
instructions added for the GELI encrypted <tt>local</tt> pool, I put them with
|
|
||||||
<b style="color:green">different color</b> to make the difference more visible.</p>
|
|
||||||
|
|
||||||
<ol>
|
|
||||||
<li>Boot from the FreeBSD USB/DVD.</li>
|
|
||||||
<li>Select the '<tt>Live CD</tt>' option.</li>
|
|
||||||
<li><tt>login: root</tt></li>
|
|
||||||
<li><tt># sh</tt></li>
|
|
||||||
<li><tt># DISKS="<b>ada0</b>"</tt></li>
|
|
||||||
<li><tt># for I in ${DISKS}; do<br>
|
|
||||||
> NUMBER=$( echo ${I} | tr -c -d '0-9' )<br>
|
|
||||||
> gpart destroy -F ${I}<br>
|
|
||||||
> gpart create -s GPT ${I}<br>
|
|
||||||
> gpart add -t freebsd-boot -l bootcode${NUMBER} -s 128k ${I}<br>
|
|
||||||
> gpart add -t freebsd-zfs -l sys${NUMBER} -s 10G ${I}<br>
|
|
||||||
> gpart add -t freebsd-zfs -l local${NUMBER} ${I}<br>
|
|
||||||
> gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 ${I}<br>
|
|
||||||
> done</tt></li>
|
|
||||||
<li><tt># zpool create -f -o cachefile=/tmp/zpool.cache sys /dev/gpt/sys0</tt></li>
|
|
||||||
<li><tt># zfs set mountpoint=none sys</tt></li>
|
|
||||||
<li><tt># zfs set checksum=fletcher4 sys</tt></li>
|
|
||||||
<li><tt># zfs set atime=off sys</tt></li>
|
|
||||||
<li><tt># zfs create sys/ROOT</tt></li>
|
|
||||||
<li><tt># zfs create -o mountpoint=/mnt sys/ROOT/default</tt></li>
|
|
||||||
<li><tt># zpool set bootfs=sys/ROOT/default sys</tt></li>
|
|
||||||
<li><tt style="color:green;font-weight:bold"># geli init -b -s 4096 -e AES-CBC -l 128 /dev/gpt/local0</tt></li>
|
|
||||||
<li><tt style="color:green;font-weight:bold"># geli attach /dev/gpt/local0</tt></li>
|
|
||||||
<li><tt style="color:green;font-weight:bold"># zpool create -f -o cachefile=/tmp/zpool.cache local /dev/gpt/local0.eli</tt></li>
|
|
||||||
<li><tt style="color:green;font-weight:bold"># zfs set mountpoint=none local</tt></li>
|
|
||||||
<li><tt style="color:green;font-weight:bold"># zfs set checksum=fletcher4 local</tt></li>
|
|
||||||
<li><tt style="color:green;font-weight:bold"># zfs set atime=off local</tt></li>
|
|
||||||
<li><tt style="color:green;font-weight:bold"># zfs create local/home</tt></li>
|
|
||||||
<li><tt style="color:green;font-weight:bold"># zfs create -o mountpoint=/mnt/root local/root</tt></li>
|
|
||||||
<li><tt># cd /usr/freebsd-dist/</tt></li>
|
|
||||||
<li><tt># for I in base.txz kernel.txz; do<br>
|
|
||||||
> tar --unlink -xvpJf ${I} -C /mnt<br>
|
|
||||||
> done</tt></li>
|
|
||||||
<li><tt># cp /tmp/zpool.cache /mnt/boot/zfs/</tt></li>
|
|
||||||
<li><tt># cat << EOF >> /mnt/boot/loader.conf<br>
|
|
||||||
> zfs_load=YES<br>
|
|
||||||
<tt style="color:green;font-weight:bold">> geom_eli_load=YES</tt><br>
|
|
||||||
> vfs.root.mountfrom="zfs:sys/ROOT/default"<br>
|
|
||||||
> EOF</tt></li>
|
|
||||||
<li><tt># cat << EOF >> /mnt/etc/rc.conf<br>
|
|
||||||
> zfs_enable=YES<br>
|
|
||||||
> EOF</tt></li>
|
|
||||||
<li><tt># :> /mnt/etc/fstab</tt></li>
|
|
||||||
<li><tt># zfs umount -a</tt></li>
|
|
||||||
<li><tt># zfs set mountpoint=legacy sys/ROOT/default</tt></li>
|
|
||||||
<li><tt style="color:green;font-weight:bold"># zfs set mountpoint=/home local/home</tt></li>
|
|
||||||
<li><tt style="color:green;font-weight:bold"># zfs set mountpoint=/root local/root</tt></li>
|
|
||||||
<li><tt># reboot</tt></li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<p>After these instructions and reboot we have these GPT partitions available,
|
|
||||||
this example is on a 4GB disk.</p>
|
|
||||||
|
|
||||||
<pre># <b>gpart show</b>
|
|
||||||
=> 34 8388541 ada0 GPT (4.0G)
|
|
||||||
34 256 1 freebsd-boot (128k)
|
|
||||||
290 2097152 2 freebsd-zfs (1.0G)
|
|
||||||
2097442 6291133 3 freebsd-zfs (3G)
|
|
||||||
|
|
||||||
# <b>gpart list | grep label</b>
|
|
||||||
label: bootcode0
|
|
||||||
label: sys0
|
|
||||||
label: local0
|
|
||||||
|
|
||||||
# <b>zpool status</b>
|
|
||||||
pool: local
|
|
||||||
state: ONLINE
|
|
||||||
scan: none requested
|
|
||||||
config:
|
|
||||||
|
|
||||||
NAME STATE READ WRITE CKSUM
|
|
||||||
sys ONLINE 0 0 0
|
|
||||||
gpt/local0.eli ONLINE 0 0 0
|
|
||||||
|
|
||||||
errors: No known data errors
|
|
||||||
|
|
||||||
pool: sys
|
|
||||||
state: ONLINE
|
|
||||||
scan: none requested
|
|
||||||
config:
|
|
||||||
|
|
||||||
NAME STATE READ WRITE CKSUM
|
|
||||||
sys ONLINE 0 0 0
|
|
||||||
gpt/sys0 ONLINE 0 0 0
|
|
||||||
|
|
||||||
errors: No known data errors</pre>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h3>4. Basic Setup after Install</h3>
|
|
||||||
|
|
||||||
<ol>
|
|
||||||
<li>Login as <b>root</b> with empty password.</li>
|
|
||||||
<pre>login: <b>root</b>
|
|
||||||
password: <b>[ENTER]</b></pre>
|
|
||||||
|
|
||||||
<li>Create initial <b>snapshot</b> after install.</li>
|
|
||||||
<tt># zfs snapshot -r sys/ROOT/default@install</tt>
|
|
||||||
|
|
||||||
<li>Set new <b>root</b> password.</li>
|
|
||||||
<tt># passwd</tt>
|
|
||||||
|
|
||||||
<li>Set machine's <b>hostname</b>.</li>
|
|
||||||
<tt># echo hostname=hostname.domain.com >> /etc/rc.conf</tt>
|
|
||||||
|
|
||||||
<li>Set proper <b>timezone</b>.</li>
|
|
||||||
<tt># tzsetup</tt>
|
|
||||||
|
|
||||||
<li>Add some <b>swap</b> space.</li>
|
|
||||||
<p>If You used the <i>Server with ...</i> type, then use this to add swap.</p>
|
|
||||||
<pre># <b>zfs create -V 1G -o org.freebsd:swap=on \
|
|
||||||
-o checksum=off \
|
|
||||||
-o sync=disabled \
|
|
||||||
-o primarycache=none \
|
|
||||||
-o secondarycache=none sys/swap</b>
|
|
||||||
# <b>swapon /dev/zvol/sys/swap</b></pre>
|
|
||||||
<p>If You used the <i>Road Warrior Laptop</i> one, then use this one below,
|
|
||||||
this was the swap space will also be encrypted.</p>
|
|
||||||
<pre># <b>zfs create -V 1G -o org.freebsd:swap=on \
|
|
||||||
-o checksum=off \
|
|
||||||
-o sync=disabled \
|
|
||||||
-o primarycache=none \
|
|
||||||
-o secondarycache=none local/swap</b>
|
|
||||||
# <b>swapon /dev/zvol/local/swap</b></pre>
|
|
||||||
|
|
||||||
<li>Create <b>snapshot</b> called <tt>configured</tt> or <tt>production</tt></li>
|
|
||||||
<p>After You configured Your fresh FreeBSD system, added needed packages
|
|
||||||
and services, create <b>snapshot</b> called <tt>configured</tt> or
|
|
||||||
<tt>production</tt> so if You mess something, You can always go back in time
|
|
||||||
to bring working configuration back. mess something.</p>
|
|
||||||
<tt># zfs snapshot -r sys/ROOT/default@configured</tt>
|
|
||||||
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h3>5. Enable Boot Environments</h3>
|
|
||||||
|
|
||||||
<p>Here are some simple instructions on how to download and enable the
|
|
||||||
<tt>beadm</tt> command line utility for easy <i>Boot Environments</i>
|
|
||||||
administration. </p>
|
|
||||||
|
|
||||||
<pre># <b>fetch https://downloads.sourceforge.net/project/beadm/beadm -o /usr/sbin/beadm</b>
|
|
||||||
# <b>chmod +x /usr/sbin/beadm</b>
|
|
||||||
# <b>rehash</b>
|
|
||||||
# <b>beadm list</b>
|
|
||||||
BE Active Mountpoint Space Policy Created
|
|
||||||
default NR / 592M static 2012-04-25 02:03</pre>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h3>6. WYSIWTF</h3>
|
|
||||||
|
|
||||||
<p>Now we have a working ZFS only FreeBSD system, I will put some example here
|
|
||||||
about what You now can do with this type of installation and of course the
|
|
||||||
<i>Boot Environments</i> feature.</p>
|
|
||||||
|
|
||||||
<h4>6.1. Create New Boot Environmnent Before Upgrade</h4>
|
|
||||||
|
|
||||||
<ol>
|
|
||||||
<li>Create new environment from the current one.</li>
|
|
||||||
<tt># beadm create upgrade</tt>
|
|
||||||
|
|
||||||
<li>Activate it.</li>
|
|
||||||
<tt># beadm activate upgrade</tt>
|
|
||||||
|
|
||||||
<li>Reboot into it.</li>
|
|
||||||
<tt># shutdown -r now</tt>
|
|
||||||
|
|
||||||
<li>Mess with it.</li>
|
|
||||||
<p>You are now free to do anything You like fo or the upgrade process,
|
|
||||||
but even if You break everything, You still have a working <tt>default</tt>
|
|
||||||
working environment.</p>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
|
|
||||||
<h4>6.2. Perform Upgrade within a Jail</h4>
|
|
||||||
|
|
||||||
<p>This concept is about creating new boot environment from the
|
|
||||||
desired one, lets call it <tt>jailed</tt>, then start that new environment
|
|
||||||
inside a FreeBSD Jail and perform upgrade there. After You have finished all
|
|
||||||
tasks related to this upgrade and You are satisfied with the achieved results,
|
|
||||||
shutdown that Jail, set the boot environment into that just upgraded Jail
|
|
||||||
called <tt>jailed</tt> and reboot into just upgraded system without any
|
|
||||||
risks.</p>
|
|
||||||
|
|
||||||
<ol>
|
|
||||||
<li>Create new boot environment called <tt>jailed</tt>.</li>
|
|
||||||
<pre># <b>beadm create -e default jailed</b>
|
|
||||||
Created successfully</pre>
|
|
||||||
|
|
||||||
<li>Create <tt>/usr/jails</tt> directory.</li>
|
|
||||||
<tt># <b>mkdir /usr/jails</b></tt>
|
|
||||||
|
|
||||||
<li>Set mount point of new boot environment to <tt>/usr/jails/jailed</tt> dir.</li>
|
|
||||||
<tt># <b>zfs set mountpoint=/usr/jails/jailed sys/ROOT/jailed</b></tt>
|
|
||||||
|
|
||||||
<li>Enable FreeBSD Jails mechanism and the <tt>jailed</tt> Jail in
|
|
||||||
<tt>/etc/rc.conf</tt> file.</li>
|
|
||||||
<tt># <b>cat << EOF >> /etc/rc.conf</b><br>
|
|
||||||
> <b>jail_enable=YES</b><br>
|
|
||||||
> <b>jail_list="jailed"</b><br>
|
|
||||||
> <b>jail_jailed_rootdir="/usr/jails/jailed"</b><br>
|
|
||||||
> <b>jail_jailed_hostname="jailed"</b><br>
|
|
||||||
> <b>jail_jailed_ip="10.20.30.40"</b><br>
|
|
||||||
> <b>jail_jailed_devfs_enable="YES"</b><br>
|
|
||||||
> <b>EOF</b></tt>
|
|
||||||
|
|
||||||
<li>Start the Jails mechanism.</li>
|
|
||||||
<pre># <b>/etc/rc.d/jail start</b>
|
|
||||||
Configuring jails:.
|
|
||||||
Starting jails: jailed.</pre>
|
|
||||||
|
|
||||||
<li>Check if the <tt>jailed</tt> Jail started.</li>
|
|
||||||
<pre># <b>jls</b>
|
|
||||||
JID IP Address Hostname Path
|
|
||||||
1 10.20.30.40 jailed /usr/jails/jailed</pre>
|
|
||||||
|
|
||||||
<li>Login into the <tt>jailed</tt> Jail.</li>
|
|
||||||
<tt># <b>jexec 1 tcsh</b></tt>
|
|
||||||
|
|
||||||
<li><b>PERFORM ACTUAL UPGRADE.</b></li>
|
|
||||||
|
|
||||||
<li>Stop the <tt>jailed</tt> Jail.</li>
|
|
||||||
<pre># <b>/etc/rc.d/jail stop</b>
|
|
||||||
Stopping jails: jailed.</pre>
|
|
||||||
|
|
||||||
<li>Disable Jails mechanism in <tt>/etc/rc.conf</tt> file.</li>
|
|
||||||
<tt># <b>sed -i '' -E s/"^jail_enable.*$"/"jail_enable=NO"/g /etc/rc.conf</b></tt>
|
|
||||||
|
|
||||||
<li>Activate just upgraded <tt>jailed</tt> boot environment.</li>
|
|
||||||
<pre># <b>bootfs-beadm activate jailed</b>
|
|
||||||
Activated successfully</pre>
|
|
||||||
|
|
||||||
<li>Restart the system into upgraded system.</li>
|
|
||||||
<tt># <b>shutdown -r now</b></tt>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
|
|
||||||
<h4>6.3. Import Boot Environmnent from Other Machine</h4>
|
|
||||||
|
|
||||||
<p>Lets assume, that You need to upgrade or do some major modification to
|
|
||||||
some of Your servers, You will then create new boot environment from the
|
|
||||||
default one, move it to other 'free' machine, perform these tasks there
|
|
||||||
and after everything is done, move the modified boot environment to the
|
|
||||||
production without any risks. You may as well trasnport that environment
|
|
||||||
into You laptop/workstation and upgrade it in a Jail like in step 6.2 of
|
|
||||||
this guide.</p>
|
|
||||||
|
|
||||||
<ol>
|
|
||||||
<li>Create new environment on the <i>production</i> server.</li>
|
|
||||||
<pre># <b>beadm create upgrade</b>
|
|
||||||
Created successfully.</pre>
|
|
||||||
|
|
||||||
<li>Send the <tt>upgrade</tt> environment to <i>test</i> server.</li>
|
|
||||||
<tt># <b>zfs send sys/ROOT/upgrade | ssh TEST zfs recv -u sys/ROOT/upgrade</b></tt>
|
|
||||||
|
|
||||||
<li>Activate the <tt>upgrade</tt> environment on the <i>test</i> server.</li>
|
|
||||||
<pre># <b>beadm activate upgrade</b>
|
|
||||||
Activated successfully.</pre>
|
|
||||||
|
|
||||||
<li>Reboot into the <tt>upgrade</tt> environment on the <i>test</i> server.</li>
|
|
||||||
<tt># <b>shutdown -r now</b></tt>
|
|
||||||
|
|
||||||
<li><b>PERFORM ACTUAL UPGRADE AFTER REBOOT.</b></li>
|
|
||||||
|
|
||||||
<li>Sent the upgraded <tt>upgrade</tt> environment onto <i>production</i> server.</li>
|
|
||||||
<tt># <b>zfs send sys/ROOT/upgrade | ssh PRODUCTION zfs recv -u sys/ROOT/upgrade</b></tt>
|
|
||||||
|
|
||||||
<li>Activate upgraded <tt>upgrade</tt> environment on the <i>production</i> server.</li>
|
|
||||||
<pre># <b>beadm activate upgrade</b>
|
|
||||||
Activated successfully.</pre>
|
|
||||||
|
|
||||||
<li>Reboot into the <tt>upgrade</tt> environment on the <i>production</i> server.</li>
|
|
||||||
<tt># <b>shutdown -r now</b></tt>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<h3>7. References</h3>
|
|
||||||
<ul>
|
|
||||||
<li><b><tt>[1]</tt></b> <a style="color:blue">http://forums.freebsd.org/showthread.php?t=10334</a></li>
|
|
||||||
<li><b><tt>[2]</tt></b> <a style="color:blue">http://forums.freebsd.org/showthread.php?t=12082</a></li>
|
|
||||||
<li><b><tt>[3]</tt></b> <a style="color:blue">http://docs.oracle.com/cd/E19963-01/pdf/820-6565.pdf</a></li>
|
|
||||||
<li><b><tt>[4]</tt></b> <a style="color:blue">http://docs.oracle.com/cd/E19963-01/html/821-1462/beadm-1m.html</a></li>
|
|
||||||
<li><b><tt>[5]</tt></b> <a style="color:blue">http://anonsvn.h3q.com/projects/freebsd-patches/wiki/manageBE</a></li>
|
|
||||||
<li><b><tt>[6]</tt></b> <a style="color:blue">https://sourceforge.net/projects/beadm/</a></li>
|
|
||||||
</ul>
|
|
||||||
</tt>
|
|
||||||
|
|
||||||
<p>The last part of the HOWTO remains the same as Year ago ...</p>
|
|
||||||
|
|
||||||
<p>You can now add your users, services and packages as usual on any FreeBSD system, have fun ;)</p>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<br>
|
|
||||||
<br>
|
|
||||||
|
|
@ -0,0 +1,499 @@
|
||||||
|
|
||||||
|
___ /\ ___
|
||||||
|
__/ /_ / \ _\ \__
|
||||||
|
____ _____/_ __/__ / _/\ ___ ___ ____ ______ __\__ _\
|
||||||
|
/ \ / / // // \ /\_/ \ / / \ / \\ \ \ / \\ \
|
||||||
|
/ / // / // // / // \\ \ \ \\ \ \\ \ \\ \ \\ \_
|
||||||
|
\_____\\____/ \__\\____//__________\\__\__\__\\____/ \_____\\__\__\\___\
|
||||||
|
|
||||||
|
The 'automount' is a devd(8) based automounter for FreeBSD.
|
||||||
|
|
||||||
|
It supports most popular file systems:
|
||||||
|
NTFS/MSDOS/exFAT/EXT2/EXT3/EXT4/UFS/XFS/HFS/MTP/ISO9660
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
I N S T A L L
|
||||||
|
===================
|
||||||
|
|
||||||
|
Use provided FreeBSD Ports/packages from here:
|
||||||
|
* sysutils/automount
|
||||||
|
|
||||||
|
.. or make manual unstallation:
|
||||||
|
|
||||||
|
# cp automount.conf /usr/local/etc/automount.conf
|
||||||
|
# cp automount_devd.conf /usr/local/etc/devd/automount_devd.conf
|
||||||
|
# cp automount /usr/local/sbin/automount
|
||||||
|
# chmod +x /usr/local/sbin/automount
|
||||||
|
# /etc/rc.d/devd restart
|
||||||
|
|
||||||
|
Now plugin Your USB thumb drive and have fun ;)
|
||||||
|
|
||||||
|
These ports/packages are needed for all filesystems:
|
||||||
|
|
||||||
|
* sysutils/e2fsprogs // EXT2/EXT3/EXT4 fsck(8)
|
||||||
|
* sysutils/xfsprogs // XFS fsck(8)
|
||||||
|
* sysutils/exfat-utils // exFAT exfatfsck(8)
|
||||||
|
* sysutils/fusefs-exfat // exFAT
|
||||||
|
* sysutils/fusefs-ntfs // NTFS (read write support)
|
||||||
|
* sysutils/fusefs-hfsfuse // HFS
|
||||||
|
* sysutils/fusefs-lkl // XFS/EXT2/EXT3/EXT4
|
||||||
|
* sysutils/fusefs-simple-mtpfs // MTP
|
||||||
|
|
||||||
|
All of the above are available as pkg(8) packages.
|
||||||
|
|
||||||
|
Shortcut:
|
||||||
|
|
||||||
|
# pkg install -y \
|
||||||
|
sysutils/e2fsprogs \
|
||||||
|
sysutils/xfsprogs \
|
||||||
|
sysutils/exfat-utils \
|
||||||
|
sysutils/fusefs-exfat \
|
||||||
|
sysutils/fusefs-ntfs \
|
||||||
|
sysutils/fusefs-hfsfuse \
|
||||||
|
sysutils/fusefs-lkl \
|
||||||
|
sysutils/fusefs-simple-mtpfs
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
C H A N G E L O G
|
||||||
|
=========================
|
||||||
|
|
||||||
|
VERSION 1.7.9 (CURRENT)
|
||||||
|
|
||||||
|
Fix XORG detection.
|
||||||
|
Implement proposed BLACKLIST_REGEX option.
|
||||||
|
Use 'sysutils/fusefs-lkl' for all ext2/ext3/ext4 mounts.
|
||||||
|
Fix exFAT detection.
|
||||||
|
Fix small problem with checking the mount state.
|
||||||
|
Implement better old directory cleanup.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
VERSION 1.7.8
|
||||||
|
|
||||||
|
Fix harmless gpart(8) rant about ugen(4) devices.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
VERSION 1.7.7
|
||||||
|
|
||||||
|
Add option to ignore system partitions like EFI or MSR.
|
||||||
|
Fix removal of dirs from unmounted filesystems.
|
||||||
|
Fix mount permissions for FAT filesystems.
|
||||||
|
Add spaces and comments in the code.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
VERSION 1.7.6
|
||||||
|
|
||||||
|
Added UZIP images support.
|
||||||
|
Added another try to mount device in read only mode.
|
||||||
|
Added optional ada(4) disks support.
|
||||||
|
Added optional md(4) devices support.
|
||||||
|
Added automatic kernel modules loading.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
VERSION 1.7.5
|
||||||
|
|
||||||
|
Add REMOVEDIRS option as default.
|
||||||
|
Add NICENAMES option to use labels instead of device names.
|
||||||
|
Use procstat(1) for faster DISPLAY environemnt searching.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
VERSION 1.7.4
|
||||||
|
|
||||||
|
Add new logo.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
VERSION 1.7.3
|
||||||
|
|
||||||
|
Use 755 permissions for FAT mounts.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
VERSION 1.7.2
|
||||||
|
|
||||||
|
Phase out support for sysutils/fusefs-ext4fuse port.
|
||||||
|
Fix UMASK for exFAT filesystems.
|
||||||
|
Fix ISO9660 mount options.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
VERSION 1.7.1
|
||||||
|
|
||||||
|
Fix exFAT mount rights.
|
||||||
|
Use USER option in config file.
|
||||||
|
Make MTP detection and mount better.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
VERSION 1.7.0
|
||||||
|
|
||||||
|
The automount has now a new co-author - Rozhuk Ivan.
|
||||||
|
New options available in automount.conf config file.
|
||||||
|
Filesystem detection/mounting reworked totally with file(1)/dd(1)/fstyp(8) as backends.
|
||||||
|
Notifications are now possible with libnotify.
|
||||||
|
Automatic detection of DISPLAY variable.
|
||||||
|
New automatic wait for device appearance.
|
||||||
|
New detection if device is a block device.
|
||||||
|
Introduction of CD-ROM support.
|
||||||
|
Automatic detection of File Manager with exo-open(1).
|
||||||
|
Option REMOVEDIRS is deprecated now.
|
||||||
|
Handle '-o large' option for FAT under FreeBSD 11.x and 12.x versions.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
VERSION 1.6.1
|
||||||
|
|
||||||
|
Fix MBR/msdosfs partition unmount issue.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
VERSION 1.6.0
|
||||||
|
|
||||||
|
Fix long boot with devd(8) because of ugen(4) devices.
|
||||||
|
Add fsck.exfat to the exFAT filesystem.
|
||||||
|
Set fsck.ext2 instead of e2fsck to the ext2 filesystem.
|
||||||
|
Set fsck.ext3 instead of e2fsck to the ext3 filesystem.
|
||||||
|
Set fsck.ext4 instead of e2fsck to the ext4 filesystem.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
VERSION 1.5.9
|
||||||
|
|
||||||
|
Decrease DELAY for sleep from '1' to '0.1' for faster mounting.
|
||||||
|
Remove __random_wait() at 'attach'.
|
||||||
|
Implement MTP mounting.
|
||||||
|
Added XFS and HFS support.
|
||||||
|
Various fixes and cleanups.
|
||||||
|
Remove '-o large' option for FAT (not supported on FreeBSD 12).
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
VERSION 1.5.8
|
||||||
|
|
||||||
|
Omit GVFS filesystem in the mount(8) listing.
|
||||||
|
Improve exFAT mount options.
|
||||||
|
Add mount_msdosfs(8) fallback fix.
|
||||||
|
Set caja as file manager in example config.
|
||||||
|
Add version argument.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
VERSION 1.5.7
|
||||||
|
|
||||||
|
Fix FAT32 mount.
|
||||||
|
Add extended options for EXFAT mounts.
|
||||||
|
Add -version option.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
VERSION 1.5.6
|
||||||
|
|
||||||
|
Implement --version option.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
VERSION 1.5.5
|
||||||
|
|
||||||
|
Rework NTFS/MSDOS/FAT detection.
|
||||||
|
Check for NTFS before FAT.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
VERSION 1.5.4
|
||||||
|
|
||||||
|
Added notification via notify-send/libnotify and wall(1). Minor bug fix.
|
||||||
|
Change 'boot sector' detection.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
VERSION 1.5.3
|
||||||
|
|
||||||
|
Fix small harmless bug - variable WAIT without default value.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
VERSION 1.5.2
|
||||||
|
|
||||||
|
Introduce smarter fstype() function to better determine filesystem.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
VERSION 1.5.1
|
||||||
|
|
||||||
|
Add -k flag to file(1) command.
|
||||||
|
Set new --version and date(1).
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
VERSION 1.5.0
|
||||||
|
|
||||||
|
Add new NTFS options.
|
||||||
|
Add nested NTFS mount attempt.
|
||||||
|
Fix devd(8) config.
|
||||||
|
Improve log messages.
|
||||||
|
Use random wait only on ATTACH action, not needed on DETACH action.
|
||||||
|
Implement random wait to eliminate race.
|
||||||
|
Implement BOOTDELAY option to wait for boot process to complete.
|
||||||
|
Fix devd(8) config (LARKIND) to match all needed devices and their partitions.
|
||||||
|
Fix typo in NTFS error message.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
VERSION 1.4.3
|
||||||
|
|
||||||
|
Only style(9) changes.
|
||||||
|
Force longnames option for msdosfs.
|
||||||
|
Remove -u option for debug.
|
||||||
|
Fix a bug when ATIME is enabled.
|
||||||
|
Add -o remove_hiberfile to NTFS-3G mount options.
|
||||||
|
Fix typo at /var/log/automount.log error message.
|
||||||
|
Use /sbin/e2fsck from FreeBSD base system.
|
||||||
|
Fix typo at /var/log/automount.log error message.
|
||||||
|
Force longnames option for msdosfs.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
VERSION 1.4.2
|
||||||
|
|
||||||
|
Implement active sleep/wait for devices that could not appear.
|
||||||
|
Add more useful information to /var/log/automount.log file.
|
||||||
|
Implement BLACKLIST option to ignore problematic devices.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
VERSION 1.4.1
|
||||||
|
|
||||||
|
Improved checking for already mounted devices.
|
||||||
|
More readable log format.
|
||||||
|
Added logging of fsck(8) output.
|
||||||
|
Added adding setuid also to /sbin/mount* when USERUMOUNT set to YES.
|
||||||
|
Added error logging of failed mounts.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
VERSION 1.4.0
|
||||||
|
|
||||||
|
Wait for smartphone to attach device, rewrite all &&-|| into if-then-else-fi syntax.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
VERSION 1.3.1
|
||||||
|
|
||||||
|
Fixed the 'detach' section (s/PREFIX/MNTPREFIX/g).
|
||||||
|
Fixed removing directories of manually (properly) unmounted filesystems.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
VERSION 1.3
|
||||||
|
|
||||||
|
Fixed inproper exFAT detection, now mounts fine.
|
||||||
|
Fixed creating mount dirs for attached devices no matter if needed or not.
|
||||||
|
Revised 'detach' section, now removes only directory that is unmounted.
|
||||||
|
Simplified FAT/NTFS sections, removed additional checks as they break
|
||||||
|
some MP3 players automount.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
VERSION 1.2.1
|
||||||
|
|
||||||
|
Added the --help page.
|
||||||
|
Removed some small bugs.
|
||||||
|
Added more options to configure features.
|
||||||
|
|
||||||
|
% /usr/local/sbin/automount --help
|
||||||
|
AUTOMOUNT is a devd(8) based automounter for FreeBSD.
|
||||||
|
|
||||||
|
It supports following file systems:
|
||||||
|
UFS/FAT/exFAT/NTFS/EXT2/EXT3/EXT4/MTP/HFS/ISO9660
|
||||||
|
|
||||||
|
Add these to mount NTFS/exFAT/EXT4/HFS/XFS/MTP respectively:
|
||||||
|
o sysutils/fusefs-ntfs
|
||||||
|
o sysutils/fusefs-exfat
|
||||||
|
o sysutils/fusefs-ext4fuse
|
||||||
|
o sysutils/fusefs-hfsfuse
|
||||||
|
o sysutils/fusefs-lkl
|
||||||
|
o sysutils/fusefs-simple-mtpfs
|
||||||
|
|
||||||
|
By default it mounts/unmounts all removable media but
|
||||||
|
it is possible to set some additional options at the
|
||||||
|
/usr/local/etc/automount.conf config file.
|
||||||
|
|
||||||
|
Below is a list of possible options with description.
|
||||||
|
|
||||||
|
MNT_PREFIX (set to /media by default)
|
||||||
|
With this options You can alter the default root
|
||||||
|
for mounting the removable media, for example to
|
||||||
|
the /mnt directory.
|
||||||
|
|
||||||
|
example: MNT_PREFIX='/media'
|
||||||
|
|
||||||
|
MNT_GROUP (wheel by default)
|
||||||
|
If set to some group name, the mount command will
|
||||||
|
chown(1) the mount directory with the group.
|
||||||
|
|
||||||
|
example: group='operator'
|
||||||
|
|
||||||
|
MNT_MODE (set to 775 by default)
|
||||||
|
Value for chmod on mount point.
|
||||||
|
|
||||||
|
FAT_ENCODING (set to en_US.UTF-8 by default)
|
||||||
|
Only used with FAT32 mounts, specifies which
|
||||||
|
encoding to use at the mount.
|
||||||
|
|
||||||
|
example: FAT_ENCODING='en_US.ISO8859-1'
|
||||||
|
|
||||||
|
FAT_CODEPAGE (set to CP866 by default)
|
||||||
|
Only used with FAT32 mounts, specifies which
|
||||||
|
code page to use at the mount.
|
||||||
|
|
||||||
|
example: FAT_CODEPAGE='cp437'
|
||||||
|
|
||||||
|
ISO9660_CODEPAGE (set to UTF-8 by default)
|
||||||
|
Only used with cd9660 mounts, specifies which
|
||||||
|
code page to use at the mount.
|
||||||
|
|
||||||
|
ATIME (set to NO by default)
|
||||||
|
When set to NO it will mount filesystems with
|
||||||
|
noatime option when possible.
|
||||||
|
|
||||||
|
example: ATIME='YES'
|
||||||
|
|
||||||
|
RETRY_COUNT (set to 3 by default)
|
||||||
|
How many times try to get file system type or try to mount.
|
||||||
|
|
||||||
|
example: RETRY_COUNT='1'
|
||||||
|
|
||||||
|
RETRY_DELAY (set to 1 second by default)
|
||||||
|
Delay beetwin retry attempt.
|
||||||
|
|
||||||
|
example: RETRY_DELAY='2.5'
|
||||||
|
|
||||||
|
USERUMOUNT (set to NO by default)
|
||||||
|
When set to YES it will 'chmod +s /sbin/umount'
|
||||||
|
which would allow an USER to unmount the file
|
||||||
|
system with their selected file manager.
|
||||||
|
|
||||||
|
example: USERUMOUNT='YES'
|
||||||
|
|
||||||
|
NOTIFY (set to NO by default)
|
||||||
|
Use 'notify-send' and 'libnotify' to show notifications
|
||||||
|
of mounting and unmounting devices on the desktop.
|
||||||
|
|
||||||
|
example: NOTIFY='YES'
|
||||||
|
|
||||||
|
WALL (set to NO by default)
|
||||||
|
Use wall(1) to show notifications of mounting and
|
||||||
|
unmounting devices on terminals of logged in users.
|
||||||
|
|
||||||
|
example: WALL='YES'
|
||||||
|
|
||||||
|
FM ('exo-open --launch FileManager' by default)
|
||||||
|
If set to file manager command, the mount will
|
||||||
|
launch the specified command after successful
|
||||||
|
mount. Works only if USER parameter is also set.
|
||||||
|
|
||||||
|
example: FM='nautilus --browser --no-desktop'
|
||||||
|
|
||||||
|
BLACKLIST (unset by default)
|
||||||
|
The automount will ignore devices defined here.
|
||||||
|
|
||||||
|
example: BLACKLIST='da0 da3s1a'
|
||||||
|
|
||||||
|
USER (root by default)
|
||||||
|
If set to some username, the mount command will
|
||||||
|
chown(1) the mount directory with the user and
|
||||||
|
its primary user group. If used with FM option
|
||||||
|
allows to launch the specified file manager after
|
||||||
|
a successful mount.
|
||||||
|
|
||||||
|
example: USER="vermaden"
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
VERSION 1.2
|
||||||
|
|
||||||
|
FAT/NTFS detection improvements.
|
||||||
|
The 'chown' now uses sets user's group.
|
||||||
|
MSDOS filesystem is now mounted with -m 644 -M 755 options by default.
|
||||||
|
Removed POPUP=YES option, just use USER + FM for simplicity.
|
||||||
|
NTFS filesystem, when mounted by mount_ntfs(8) uses -u and -g options.
|
||||||
|
Even more simplified 'detach' section.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
VERSION 1.1
|
||||||
|
|
||||||
|
I removed the state_lock and stat_unlock mechanisms as they appeared to be
|
||||||
|
not needed, I have shufled with 3 drives all the time and the 'integrity'
|
||||||
|
has not been lost, at it was a lot faster, because the lock always had to
|
||||||
|
wait for the 'slowest' drive (in term of initializing the device, like USB
|
||||||
|
hard drive).
|
||||||
|
|
||||||
|
I simplified the 'attach' section a lot, now each filesystem contains only
|
||||||
|
check/fsck (if possible), mount and log info.
|
||||||
|
|
||||||
|
I also simplified and improved the 'detach' section a little.
|
||||||
|
|
||||||
|
I added an option to automatically launch the set-up in config file manager.
|
||||||
|
|
||||||
|
These are options that I currently successfully use for NAUTILUS file
|
||||||
|
manager. You need to set-up all three of them to make it work.
|
||||||
|
|
||||||
|
| POPUP=YES
|
||||||
|
| FM="nautilus --browser --no-desktop"
|
||||||
|
| USER=vermaden
|
||||||
|
|
||||||
|
My whole config looks like that now:
|
||||||
|
|
||||||
|
| USERUMOUNT=YES
|
||||||
|
| POPUP=YES
|
||||||
|
| FM="nautilus --browser --no-desktop"
|
||||||
|
| USER=vermaden
|
||||||
|
| ENCODING=pl_PL.ISO8859-2
|
||||||
|
| CODEPAGE=cp852
|
||||||
|
|
||||||
|
All latest updates are available at GITHUB repository:
|
||||||
|
https://github.com/vermaden/automount
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
VERSION 1.0
|
||||||
|
|
||||||
|
AUTOMOUNT is devd(8) based flexible yet very simple automounter for FreeBSD.
|
||||||
|
|
||||||
|
Currently it supports these file systems:
|
||||||
|
-- NTFS requires sysutils/fusefs-ntfs for R/W
|
||||||
|
-- FAT/FAT32
|
||||||
|
-- exFAT requires sysutils/fusefs-exfat
|
||||||
|
-- EXT2
|
||||||
|
-- EXT3
|
||||||
|
-- EXT4 requires sysutils/fusefs-ext4fuse
|
||||||
|
-- UFS
|
||||||
|
|
||||||
|
It keeps state of the mounted devices at /var/run/automount.state and logs
|
||||||
|
all activities to /var/log/automount.log file.
|
||||||
|
|
||||||
|
The place for the script is at /usr/local/sbin/automount.sh executable.
|
||||||
|
|
||||||
|
The only additional configuration it requires is to add these lines as
|
||||||
|
/usr/local/etc/devd/automount_devd.conf file, which would allow it to work.
|
||||||
|
|
||||||
|
Remember to restart /etc/rc.d/devd daemon after adding
|
||||||
|
/usr/local/etc/devd/automount_devd.conf file.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Have Fun ;)
|
||||||
|
vermaden
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
beadm
|
|
||||||
=====
|
|
||||||
|
|
||||||
FreeBSD utility to manage Boot Environments on ZFS filesystems.
|
|
||||||
|
|
@ -0,0 +1,779 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Copyright (c) 2012-2024 Slawomir Wojciech Wojtczak <vermaden@interia.pl>
|
||||||
|
# Copyright (c) 2019 Rozhuk Ivan <rozhuk.im@gmail.com>
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that following conditions are met:
|
||||||
|
# 1. Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
# 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS 'AS IS' AND ANY
|
||||||
|
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
PATH=${PATH}:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
|
||||||
|
|
||||||
|
__usage() {
|
||||||
|
cat << EOF
|
||||||
|
AUTOMOUNT is a devd(8) based automounter for FreeBSD.
|
||||||
|
|
||||||
|
It supports following file systems:
|
||||||
|
UFS/FAT/exFAT/NTFS/EXT2/EXT3/EXT4/MTP/HFS/ISO9660
|
||||||
|
|
||||||
|
Add these to mount NTFS/exFAT/EXT4/HFS/XFS/MTP respectively:
|
||||||
|
o sysutils/fusefs-ntfs
|
||||||
|
o sysutils/fusefs-exfat
|
||||||
|
o sysutils/fusefs-hfsfuse
|
||||||
|
o sysutils/fusefs-lkl
|
||||||
|
o sysutils/fusefs-simple-mtpfs
|
||||||
|
|
||||||
|
By default it mounts/unmounts all removable media but
|
||||||
|
it is possible to set some additional options at the
|
||||||
|
/usr/local/etc/automount.conf config file.
|
||||||
|
|
||||||
|
Below is a list of possible options with description.
|
||||||
|
|
||||||
|
MNT_PREFIX (set to /media by default)
|
||||||
|
With this options You can alter the default root
|
||||||
|
for mounting the removable media, for example to
|
||||||
|
the /mnt directory.
|
||||||
|
|
||||||
|
example: MNT_PREFIX='/media'
|
||||||
|
|
||||||
|
MNT_GROUP (wheel by default)
|
||||||
|
If set to some group name, the mount command will
|
||||||
|
chown(1) the mount directory with the group.
|
||||||
|
|
||||||
|
example: group='operator'
|
||||||
|
|
||||||
|
MNT_MODE (set to 775 by default)
|
||||||
|
Value for chmod on mount point.
|
||||||
|
|
||||||
|
FAT_ENCODING (set to en_US.UTF-8 by default)
|
||||||
|
Only used with FAT32 mounts, specifies which
|
||||||
|
encoding to use at the mount.
|
||||||
|
|
||||||
|
example: FAT_ENCODING='en_US.ISO8859-1'
|
||||||
|
|
||||||
|
FAT_CODEPAGE (set to CP866 by default)
|
||||||
|
Only used with FAT32 mounts, specifies which
|
||||||
|
code page to use at the mount.
|
||||||
|
|
||||||
|
example: FAT_CODEPAGE='cp437'
|
||||||
|
|
||||||
|
ISO9660_CODEPAGE (set to UTF-8 by default)
|
||||||
|
Only used with cd9660 mounts, specifies which
|
||||||
|
code page to use at the mount.
|
||||||
|
|
||||||
|
ATIME (set to NO by default)
|
||||||
|
When set to NO it will mount filesystems with
|
||||||
|
noatime option when possible.
|
||||||
|
|
||||||
|
example: ATIME='YES'
|
||||||
|
|
||||||
|
RETRY_COUNT (set to 3 by default)
|
||||||
|
How many times try to get file system type or try to mount.
|
||||||
|
|
||||||
|
example: RETRY_COUNT='1'
|
||||||
|
|
||||||
|
RETRY_DELAY (set to 1 second by default)
|
||||||
|
Delay beetwin retry attempt.
|
||||||
|
|
||||||
|
example: RETRY_DELAY='2.5'
|
||||||
|
|
||||||
|
USERUMOUNT (set to NO by default)
|
||||||
|
When set to YES it will 'chmod +s /sbin/umount'
|
||||||
|
which would allow an USER to unmount the file
|
||||||
|
system with their selected file manager.
|
||||||
|
|
||||||
|
example: USERUMOUNT='YES'
|
||||||
|
|
||||||
|
NOTIFY (set to NO by default)
|
||||||
|
Use 'notify-send' and 'libnotify' to show notifications
|
||||||
|
of mounting and unmounting devices on the desktop.
|
||||||
|
|
||||||
|
example: NOTIFY='YES'
|
||||||
|
|
||||||
|
WALL (set to NO by default)
|
||||||
|
Use wall(1) to show notifications of mounting and
|
||||||
|
unmounting devices on terminals of logged in users.
|
||||||
|
|
||||||
|
example: WALL='YES'
|
||||||
|
|
||||||
|
FM ('exo-open --launch FileManager' by default)
|
||||||
|
If set to file manager command, the mount will
|
||||||
|
launch the specified command after successful
|
||||||
|
mount. Works only if USER parameter is also set.
|
||||||
|
|
||||||
|
example: FM='nautilus --browser --no-desktop'
|
||||||
|
|
||||||
|
BLACKLIST (unset by default)
|
||||||
|
The automount will ignore devices defined here.
|
||||||
|
|
||||||
|
example: BLACKLIST='da0 da3s1a'
|
||||||
|
|
||||||
|
|
||||||
|
BLACKLIST_REGEX (unset by default)
|
||||||
|
The boolean flag option complements the above BLACKLIST option
|
||||||
|
if one wants regex match instead of exact match for ignoring devices.
|
||||||
|
Below will ignore all partitions ada0p1/ada0p2/... of ada0 device.
|
||||||
|
|
||||||
|
example: BLACKLIST='ada0'
|
||||||
|
BLACKLIST_REGEX=true
|
||||||
|
|
||||||
|
USER (root by default)
|
||||||
|
If set to some username, the mount command will
|
||||||
|
chown(1) the mount directory with the user and
|
||||||
|
its primary user group. If used with FM option
|
||||||
|
allows to launch the specified file manager after
|
||||||
|
a successful mount.
|
||||||
|
|
||||||
|
example: USER="vermaden"
|
||||||
|
|
||||||
|
REMOVEDIRS (set to YES by default)
|
||||||
|
If set to YES the automount(8) will remove /media dir after unmount.
|
||||||
|
|
||||||
|
example: REMOVEDIRS=NO
|
||||||
|
|
||||||
|
NICENAMES (set to NO by default)
|
||||||
|
If set to YES the device/filesystem label will be used for /media dir name.
|
||||||
|
|
||||||
|
example: NICENAMES=YES
|
||||||
|
|
||||||
|
IGNORE_SYS_PARTS (set to NO by default)
|
||||||
|
If set to YES automount(8) will ignore system partitions like EFI or MSR.
|
||||||
|
|
||||||
|
example: IGNORE_SYS_PARTS=YES
|
||||||
|
|
||||||
|
EOF
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# display version if needed
|
||||||
|
if [ "${1}" = '--version' -o \
|
||||||
|
"${1}" = '-version' -o \
|
||||||
|
"${1}" = 'version' -o \
|
||||||
|
"${1}" = '-v' ]
|
||||||
|
then
|
||||||
|
echo
|
||||||
|
echo " ___ /\ ___ "
|
||||||
|
echo " __/ /_ / \ _\ \__ "
|
||||||
|
echo " ____ _____/_ __/__ / _/\ ___ ___ ____ ______ __\__ _\ "
|
||||||
|
echo " / \ / / // // \ /\_/ \ / / \ / \\\ \ \ / \\\ \ "
|
||||||
|
echo " / / // / // // / // \\\ \ \ \\\ \ \\\ \ \\\ \ \\\ \_ "
|
||||||
|
echo " \_____\\\____/ \__\\\____//__________\\\__\__\__\\\____/ \_____\\\__\__\\\___\ "
|
||||||
|
echo
|
||||||
|
echo "automount 1.8.0 2024/03/05"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# display help if needed
|
||||||
|
if [ "${1}" = "-h" -o \
|
||||||
|
"${1}" = "--h" -o \
|
||||||
|
"${1}" = "-help" -o \
|
||||||
|
"${1}" = "--help" -o \
|
||||||
|
"${#}" -eq "0" -o \
|
||||||
|
"${#}" -eq "1" ]
|
||||||
|
then
|
||||||
|
__usage
|
||||||
|
fi
|
||||||
|
|
||||||
|
# read configuration file
|
||||||
|
if [ -f /usr/local/etc/automount.conf ] ; then
|
||||||
|
. /usr/local/etc/automount.conf
|
||||||
|
fi
|
||||||
|
|
||||||
|
# default values for global variables
|
||||||
|
: ${MNT_PREFIX='/media'} # mount prefix
|
||||||
|
: ${MNT_GROUP='wheel'} # use WHEEL group for popup
|
||||||
|
: ${MNT_MODE='775'} # mount point mode
|
||||||
|
: ${FAT_ENCODING='en_US.UTF-8'} # US/Canada
|
||||||
|
: ${FAT_CODEPAGE='cp437'} # US/Canada
|
||||||
|
: ${ISO9660_CODEPAGE='UTF-8'} # UTF-8
|
||||||
|
: ${ATIME='NO'} # when NO mount with noatime
|
||||||
|
: ${RETRY_COUNT='5'} # retry count
|
||||||
|
: ${RETRY_DELAY='2'} # retry delay time
|
||||||
|
: ${USERUMOUNT='NO'} # when YES add suid bit to umount(8)
|
||||||
|
: ${NOTIFY='NO'} # use notify-send(1) (devel/libnotify)
|
||||||
|
: ${WALL='NO'} # use wall(1)
|
||||||
|
: ${FM='exo-open --launch FileManager'} # which file manager to use
|
||||||
|
: ${LOG_FILE='/var/log/automount.log'} # log file
|
||||||
|
: ${LOG_DATEFMT='%Y-%m-%d %H:%M:%S'} # 2012-02-20 07:49:09
|
||||||
|
: ${STATE="/var/run/automount.state"} # current state file
|
||||||
|
: ${USER="root"} # which user to use for popup
|
||||||
|
: ${REMOVEDIRS='YES'} # remove /media dir after unmount
|
||||||
|
: ${NICENAMES='NO'} # use device label for /media dir name
|
||||||
|
: ${IGNORE_SYS_PARTS='NO'} # ignore system partitions like EFI or MSR
|
||||||
|
|
||||||
|
# init of main variables
|
||||||
|
DEV="/dev/${1}"
|
||||||
|
UID=$( id -u ${USER} )
|
||||||
|
GID=$( pw group show -n ${MNT_GROUP} | awk -F':' '{print $3}' )
|
||||||
|
if [ ${?} -ne 0 ]
|
||||||
|
then
|
||||||
|
__log "${MNT_GROUP}: invalid group"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# process ${USERUMOUNT} option
|
||||||
|
case ${USERUMOUNT} in
|
||||||
|
([Yy][Ee][Ss])
|
||||||
|
chmod u+s /sbin/umount 1> /dev/null 2>&1 # WHEEL group member
|
||||||
|
chmod u+s /sbin/mount* 1> /dev/null 2>&1 # WHEEL group member
|
||||||
|
sysctl -q vfs.usermount=1 1> /dev/null 2>&1 # allow user to mount
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# read only filesystem types for __guess_fs_type() function
|
||||||
|
readonly FS_TYPE_UNKNOWN=0
|
||||||
|
readonly FS_TYPE_ISO9660=1
|
||||||
|
readonly FS_TYPE_UFS=8
|
||||||
|
readonly FS_TYPE_EXT2=9
|
||||||
|
readonly FS_TYPE_EXT3=10
|
||||||
|
readonly FS_TYPE_EXT4=11
|
||||||
|
readonly FS_TYPE_XFS=12
|
||||||
|
readonly FS_TYPE_HFS=13
|
||||||
|
readonly FS_TYPE_FAT=32
|
||||||
|
readonly FS_TYPE_EXFAT=33
|
||||||
|
readonly FS_TYPE_NTFS=34
|
||||||
|
readonly FS_TYPE_MTP=128
|
||||||
|
|
||||||
|
# FUNCTION: guess filesystem type from device
|
||||||
|
__guess_fs_type() { # 1=DEV
|
||||||
|
# first time guess with file(1) tool
|
||||||
|
unset FS_TYPE
|
||||||
|
local FS_TYPE=$( file -r -b -L -s ${1} 2> /dev/null | sed -E 's/label:\ \".*\"//g' )
|
||||||
|
case ${FS_TYPE} in
|
||||||
|
(*ISO\ 9660*) return ${FS_TYPE_ISO9660} ;;
|
||||||
|
(*Unix\ Fast\ File*) return ${FS_TYPE_UFS} ;;
|
||||||
|
(*ext2*) return ${FS_TYPE_EXT2} ;;
|
||||||
|
(*ext3*) return ${FS_TYPE_EXT3} ;;
|
||||||
|
(*ext4*) return ${FS_TYPE_EXT4} ;;
|
||||||
|
(*SGI\ XFS*) return ${FS_TYPE_XFS} ;;
|
||||||
|
(*Macintosh\ HFS*) return ${FS_TYPE_HFS} ;;
|
||||||
|
esac
|
||||||
|
# second time guess with file(1) tool with -k option
|
||||||
|
# (do not stop at the first match and keep going)
|
||||||
|
unset FS_TYPE
|
||||||
|
local FS_TYPE=$( file -k -r -b -L -s ${1} 2> /dev/null | tr '\n' ' ' | sed -E 's/label:\ \".*\"//g' )
|
||||||
|
case ${FS_TYPE} in
|
||||||
|
(*Unix\ Fast\ File*) return ${FS_TYPE_UFS} ;;
|
||||||
|
(*NTFS*) return ${FS_TYPE_NTFS} ;;
|
||||||
|
(*ExFAT*) return ${FS_TYPE_EXFAT} ;;
|
||||||
|
(*\ FAT\ *|*MSDOS*) return ${FS_TYPE_FAT} ;;
|
||||||
|
esac
|
||||||
|
# try with fstyp(8) last (exFAT on UFS issue)
|
||||||
|
unset FS_TYPE
|
||||||
|
local FS_TYPE=$( fstyp ${1} 2> /dev/null )
|
||||||
|
case ${FS_TYPE} in
|
||||||
|
(cd9660) return ${FS_TYPE_ISO9660} ;;
|
||||||
|
(ufs) return ${FS_TYPE_UFS} ;;
|
||||||
|
(ext2fs) return ${FS_TYPE_EXT2} ;;
|
||||||
|
(msdosfs) return ${FS_TYPE_FAT} ;;
|
||||||
|
(exfat) return ${FS_TYPE_EXFAT} ;;
|
||||||
|
(ntfs) return ${FS_TYPE_NTFS} ;;
|
||||||
|
esac
|
||||||
|
# magic detection code with dd(8)
|
||||||
|
unset FS_TYPE
|
||||||
|
local FS_TYPE=$( dd if="${1}" conv=sync count=1 bs=1k 2> /dev/null | strings | head -1 )
|
||||||
|
case ${FS_TYPE} in
|
||||||
|
(*EXFAT*) return ${FS_TYPE_EXFAT} ;;
|
||||||
|
esac
|
||||||
|
return ${FS_TYPE_UNKNOWN}
|
||||||
|
}
|
||||||
|
|
||||||
|
# FUNCTION: add state to the ${STATE} file
|
||||||
|
__state_add() { # 1=DEV 2=PROVIDER 3=MNT
|
||||||
|
if [ -f ${STATE} ]
|
||||||
|
then
|
||||||
|
if grep -E "${3}$" ${STATE} 1> /dev/null 2> /dev/null
|
||||||
|
then
|
||||||
|
__log "${1}: duplicated '${STATE}'"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
echo "${1} ${2} ${3}" >> ${STATE}
|
||||||
|
if [ "${NOTIFY}" = YES ]
|
||||||
|
then
|
||||||
|
__show_message "Device '${1}' mounted on '${3}' directory."
|
||||||
|
fi
|
||||||
|
if [ "${WALL}" = YES ]
|
||||||
|
then
|
||||||
|
echo "automount: Device '${1}' mounted on '${3}' directory." | wall
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# FUNCTION: remove state from the ${STATE} file
|
||||||
|
__state_remove() { # 1=MNT
|
||||||
|
if [ -f ${STATE} ]
|
||||||
|
then
|
||||||
|
# backslash the slashes ;)
|
||||||
|
BSMNT=$( echo ${1} | sed 's/\//\\\//g' )
|
||||||
|
sed -i '' "/${BSMNT}\$/d" ${STATE}
|
||||||
|
if [ "${NOTIFY}" = YES ]
|
||||||
|
then
|
||||||
|
__show_message "Device '${1}' unmounted from '${3}' directory."
|
||||||
|
fi
|
||||||
|
if [ "${WALL}" = YES ]
|
||||||
|
then
|
||||||
|
echo "automount: Device '${1}' unmounted from '${3}' directory." | wall
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# FUNCTION: add message to the ${LOG_FILE} file
|
||||||
|
__log() { # @=MESSAGE
|
||||||
|
echo $( date +"${LOG_DATEFMT}" ) "${@}" >> "${LOG_FILE}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# FUNCTION: remove temp mount dir from ${MNT_PREFIX} path (like /media/da0 dir)
|
||||||
|
__remove_dir() { # 1=TARGET
|
||||||
|
if [ "${REMOVEDIRS}" = YES ]
|
||||||
|
then
|
||||||
|
if [ -d "${1}" ]
|
||||||
|
then
|
||||||
|
sleep 1
|
||||||
|
# find "${1}" -type d -empty -maxdepth 1 -exec rm -r {} '+' 2> /dev/null
|
||||||
|
find "${MNT_PREFIX}" -depth 1 -empty -prune -delete 2> /dev/null
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# FUNCTION: display wall(1) and/or notify-send(1) message
|
||||||
|
__show_message() { # 1=MESSAGE
|
||||||
|
case ${WALL} in
|
||||||
|
([Yy][Ee][Ss])
|
||||||
|
echo "automount: ${1}" | wall
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
case ${NOTIFY} in
|
||||||
|
([Yy][Ee][Ss])
|
||||||
|
local __DISPLAY_IDS=$( ps aew | sed -n 's|.*DISPLAY=\([-_a-zA-Z0-9:.]*\).*|\1|p' | sort -u | tr '\n' ' ' )
|
||||||
|
for __DISPLAY_ID in ${__DISPLAY_IDS}
|
||||||
|
do
|
||||||
|
local __USER=$( ps aewj | grep "DISPLAY=${__DISPLAY_ID}" | awk '{print $1;}' | sort -u | tr -cd '[:print:]' )
|
||||||
|
if [ -z "${__USER}" ]
|
||||||
|
then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
su -l "${__USER}" -c "env DISPLAY=${__DISPLAY_ID} notify-send automount '${1}' &" 1> /dev/null 2>&1
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# FUNCTION: check if device or mountpoint not already mounted
|
||||||
|
__check_already_mounted() { # 1=DEV 2=MNT
|
||||||
|
local MOUNT=$( mount )
|
||||||
|
if echo "${MOUNT}" | grep -q "^${1} on "
|
||||||
|
then
|
||||||
|
local MOUNT_POINT=$( echo "${MOUNT}" | grep "^${1} on " | cut -d ' ' -f 3-255 | cut -d '(' -f 1 | sed s/.$// )
|
||||||
|
__log "${DEV}: already mounted on '${MOUNT_POINT}' mount point"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if echo "${MOUNT}" | grep -q " on ${2} "
|
||||||
|
then
|
||||||
|
local DEVICE=$( echo "${MOUNT}" | grep " on ${2} " | awk '{print $1}' )
|
||||||
|
__log "${DEVICE}: already mounted on '${2}' mount point"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# FUNCTION: wait for device to appear (sometimes needed)
|
||||||
|
__wait_for_device() { # 1=DEV
|
||||||
|
# do not wait for MTP and CD-ROM devices
|
||||||
|
case ${1} in
|
||||||
|
(*ugen*|iso9660*)
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
# try to read from device to ensure that it alive
|
||||||
|
local COUNT=0
|
||||||
|
while ! dd if="${1}" of=/dev/null conv=sync count=1 bs=8k 1> /dev/null 2>&1
|
||||||
|
do
|
||||||
|
if [ ! -e "${1}" ]
|
||||||
|
then
|
||||||
|
__log "${1}: device gone"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
COUNT=$(( ${COUNT} + 1 ))
|
||||||
|
if [ ${COUNT} -ge ${RETRY_COUNT} ]
|
||||||
|
then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
sleep "${RETRY_DELAY}"
|
||||||
|
__log "${1}: wait for device retry ${COUNT}/${RETRY_COUNT}"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# FUNCTION: check if device is a block device
|
||||||
|
__check_block_device() { # 1=DEV
|
||||||
|
# first check if its block device
|
||||||
|
if ! fstyp ${1} 1> /dev/null 2>&1
|
||||||
|
then
|
||||||
|
__log "${DEV}: not a block device"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# main ATTACH/DETACH block
|
||||||
|
case ${2} in
|
||||||
|
(attach)
|
||||||
|
# check if device still exists
|
||||||
|
if [ ! -e "${DEV}" ]
|
||||||
|
then
|
||||||
|
__log "${DEV}: device does not exist"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
__log "${DEV}: attach"
|
||||||
|
|
||||||
|
# ignore system partitions like EFI or MSR
|
||||||
|
if [ "${IGNORE_SYS_PARTS}" = 'YES' ]
|
||||||
|
then
|
||||||
|
SYS_DEV=$( echo ${1} | grep -E -o '^[a-z]+[0-9]+' )
|
||||||
|
SYS_GPART=$( gpart show -p -r ${SYS_DEV} 2> /dev/null | sed 's@=>@@g' | grep " ${1} " | awk '{print $4}' )
|
||||||
|
case ${SYS_GPART} in
|
||||||
|
(c12a7328-f81f-11d2-ba4b-00a0c93ec93b) exit 0 ;;
|
||||||
|
(e3c9e316-0b5c-4db8-817d-f92df00215ae) exit 0 ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# code for NICENAMES mounting instead of the /dev/${DEV} default
|
||||||
|
MNT_CANDIDATE=$( fstyp -l "/dev/${1}" 2> /dev/null | cut -d " " -f 2-99 | tr ' ' '-' )
|
||||||
|
if [ "${NICENAMES}" = "YES" -a -n "${MNT_CANDIDATE}" ]
|
||||||
|
then
|
||||||
|
# check if dir exists
|
||||||
|
if [ -e "${MNT_PREFIX}/${MNT_CANDIDATE}" ]
|
||||||
|
then
|
||||||
|
# check if something is already mounted there and increment if it is
|
||||||
|
if mount | grep -q " ${MNT_PREFIX}/${MNT_CANDIDATE} "
|
||||||
|
then
|
||||||
|
COUNT=1
|
||||||
|
while true
|
||||||
|
do
|
||||||
|
COUNT=$(( ${COUNT} + 1 ))
|
||||||
|
[ ! -e "${MNT_PREFIX}/${MNT_CANDIDATE}-${COUNT}" ] && break
|
||||||
|
done
|
||||||
|
MNT="${MNT_PREFIX}/${MNT_CANDIDATE}-${COUNT}"
|
||||||
|
else
|
||||||
|
# dir exists but its not mounted
|
||||||
|
MNT="${MNT_PREFIX}/${MNT_CANDIDATE}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# dir does not exist
|
||||||
|
MNT="${MNT_PREFIX}/${MNT_CANDIDATE}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# device/filesystem without label
|
||||||
|
MNT="${MNT_PREFIX}/${1}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# blacklist check
|
||||||
|
if [ -n "${BLACKLIST}" ]
|
||||||
|
then
|
||||||
|
for I in ${BLACKLIST}
|
||||||
|
do
|
||||||
|
if [ "${1}" = "${I}" ]
|
||||||
|
then
|
||||||
|
__log "${DEV}: device blocked by BLACKLIST option"
|
||||||
|
exit 0
|
||||||
|
elif [ -n "${BLACKLIST_REGEX}" ] && echo ${DEV} | grep -q "${I}" 1> /dev/null 2> /dev/null
|
||||||
|
then
|
||||||
|
__log "${DEV}: device blocked by BLACKLIST_REGEX option"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# check is device already mounted
|
||||||
|
__check_already_mounted "${DEV}" "${MNT}"
|
||||||
|
|
||||||
|
# make sure that data can be read from device
|
||||||
|
__wait_for_device "${DEV}"
|
||||||
|
|
||||||
|
# load needed kernel modules
|
||||||
|
kldload fusefs 1> /dev/null 2> /dev/null
|
||||||
|
kldload geom_uzip 1> /dev/null 2> /dev/null
|
||||||
|
|
||||||
|
# detect filesysytem type
|
||||||
|
case ${1} in
|
||||||
|
(iso9660*)
|
||||||
|
FS_TYPE=${FS_TYPE_ISO9660}
|
||||||
|
;;
|
||||||
|
(ugen*)
|
||||||
|
FS_TYPE=${FS_TYPE_MTP}
|
||||||
|
;;
|
||||||
|
(cd*)
|
||||||
|
__guess_fs_type "${DEV}"
|
||||||
|
FS_TYPE=${?}
|
||||||
|
;;
|
||||||
|
(md*.uzip|md*|ada*|da*|mmcsd*)
|
||||||
|
__check_block_device "${DEV}"
|
||||||
|
__guess_fs_type "${DEV}"
|
||||||
|
FS_TYPE=${?}
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# process ATIME option
|
||||||
|
case ${ATIME} in
|
||||||
|
([Nn][Oo]) OPTS="-o noatime" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# filesystem options abstraction layer
|
||||||
|
case ${FS_TYPE} in
|
||||||
|
(${FS_TYPE_ISO9660})
|
||||||
|
FS_CHECK_CMD=''
|
||||||
|
FS_CHECK_ARGS=''
|
||||||
|
FS_MOUNT_CMD='mount'
|
||||||
|
FS_MOUNT_ARGS="-t cd9660 -o -e,-C=${ISO9660_CODEPAGE} ${DEV} ${MNT}"
|
||||||
|
;;
|
||||||
|
(${FS_TYPE_UFS})
|
||||||
|
FS_CHECK_CMD='fsck_ufs'
|
||||||
|
FS_CHECK_ARGS="-C -y"
|
||||||
|
FS_MOUNT_CMD='mount'
|
||||||
|
FS_MOUNT_ARGS="-t ufs ${OPTS} ${DEV} ${MNT}"
|
||||||
|
;;
|
||||||
|
(${FS_TYPE_EXT2})
|
||||||
|
FS_CHECK_PORT='sysutils/e2fsprogs'
|
||||||
|
FS_CHECK_CMD='fsck.ext2'
|
||||||
|
FS_CHECK_ARGS="-y"
|
||||||
|
FS_MOUNT_PORT='sysutils/fusefs-lkl'
|
||||||
|
FS_MOUNT_CMD='lklfuse'
|
||||||
|
FS_MOUNT_ARGS="-o type=ext2 -o allow_other -o intr -o uid=${UID} -o gid=${GID} -o umask=002 ${DEV} ${MNT}"
|
||||||
|
;;
|
||||||
|
(${FS_TYPE_EXT3})
|
||||||
|
FS_CHECK_PORT='sysutils/e2fsprogs'
|
||||||
|
FS_CHECK_CMD='fsck.ext3'
|
||||||
|
FS_CHECK_ARGS="-y"
|
||||||
|
FS_MOUNT_PORT='sysutils/fusefs-lkl'
|
||||||
|
FS_MOUNT_CMD='lklfuse'
|
||||||
|
FS_MOUNT_ARGS="-o type=ext3 -o allow_other -o intr -o uid=${UID} -o gid=${GID} -o umask=002 ${DEV} ${MNT}"
|
||||||
|
;;
|
||||||
|
(${FS_TYPE_EXT4})
|
||||||
|
FS_CHECK_PORT='sysutils/e2fsprogs'
|
||||||
|
FS_CHECK_CMD='fsck.ext4'
|
||||||
|
FS_CHECK_ARGS="-y"
|
||||||
|
FS_MOUNT_PORT='sysutils/fusefs-lkl'
|
||||||
|
FS_MOUNT_CMD='lklfuse'
|
||||||
|
FS_MOUNT_ARGS="-o type=ext4 -o allow_other -o intr -o uid=${UID} -o gid=${GID} -o umask=002 ${DEV} ${MNT}"
|
||||||
|
;;
|
||||||
|
(${FS_TYPE_XFS})
|
||||||
|
FS_CHECK_PORT='sysutils/xfsprogs'
|
||||||
|
FS_CHECK_CMD='xfs_repair'
|
||||||
|
FS_CHECK_ARGS="-d"
|
||||||
|
FS_MOUNT_CMD='lklfuse'
|
||||||
|
FS_MOUNT_ARGS="-o type=xfs -o allow_other -o uid=${UID} -o gid=${GID} ${DEV} ${MNT}"
|
||||||
|
FS_MOUNT_PORT='sysutils/fusefs-lkl'
|
||||||
|
;;
|
||||||
|
(${FS_TYPE_HFS})
|
||||||
|
FS_CHECK_CMD=''
|
||||||
|
FS_CHECK_ARGS=''
|
||||||
|
FS_MOUNT_CMD='hfsfuse'
|
||||||
|
FS_MOUNT_ARGS="--force ${OPTS} ${DEV} ${MNT}"
|
||||||
|
FS_MOUNT_PORT='sysutils/fusefs-hfsfuse'
|
||||||
|
;;
|
||||||
|
(${FS_TYPE_FAT})
|
||||||
|
# FreeBSD 12.x and later does not support/need '-o large' option
|
||||||
|
case $( sysctl -n kern.osrelease ) in
|
||||||
|
(10*) LARGE="-o large" ;;
|
||||||
|
(11*) LARGE="-o large" ;;
|
||||||
|
(*) LARGE="" ;;
|
||||||
|
esac
|
||||||
|
FS_CHECK_CMD='fsck_msdosfs'
|
||||||
|
FS_CHECK_ARGS="-C -y"
|
||||||
|
FS_MOUNT_CMD='mount_msdosfs'
|
||||||
|
FS_MOUNT_ARGS="-o longnames -m ${MNT_MODE} -M ${MNT_MODE} -D ${FAT_CODEPAGE} -L ${FAT_ENCODING} -u ${UID} -g ${GID} ${OPTS} ${LARGE} ${DEV} ${MNT}"
|
||||||
|
;;
|
||||||
|
(${FS_TYPE_EXFAT})
|
||||||
|
FS_CHECK_PORT='sysutils/exfat-utils'
|
||||||
|
FS_CHECK_CMD='fsck.exfat'
|
||||||
|
FS_CHECK_ARGS="-y"
|
||||||
|
FS_MOUNT_CMD='mount.exfat'
|
||||||
|
FS_MOUNT_UMASK=$( printf "%03o" $((~0775&0777)) )
|
||||||
|
FS_MOUNT_ARGS="-o uid=${UID} -o gid=${GID} -o umask=${FS_MOUNT_UMASK} ${OPTS} ${DEV} ${MNT}"
|
||||||
|
FS_MOUNT_PORT='sysutils/fusefs-exfat'
|
||||||
|
;;
|
||||||
|
(${FS_TYPE_NTFS})
|
||||||
|
FS_CHECK_CMD=''
|
||||||
|
FS_CHECK_ARGS=''
|
||||||
|
if /usr/bin/which -s ntfs-3g
|
||||||
|
then
|
||||||
|
FS_MOUNT_CMD='ntfs-3g'
|
||||||
|
FS_MOUNT_ARGS="-o recover ${OPTS} ${DEV} ${MNT}"
|
||||||
|
FS_MOUNT_PORT='sysutils/fusefs-ntfs'
|
||||||
|
else
|
||||||
|
FS_MOUNT_CMD='mount_ntfs'
|
||||||
|
FS_MOUNT_ARGS="-u root -g ${MNT_GROUP} ${OPTS} ${DEV} ${MNT}"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
(${FS_TYPE_MTP})
|
||||||
|
FS_PORT='sysutils/fusefs-simple-mtpfs'
|
||||||
|
FS_CHECK_CMD=''
|
||||||
|
FS_CHECK_ARGS=''
|
||||||
|
FS_MOUNT_CMD='simple-mtpfs'
|
||||||
|
if ! /usr/bin/which -s "${FS_MOUNT_CMD}"
|
||||||
|
then
|
||||||
|
__log "command '${FS_MOUNT_CMD}' not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
PHONEDEV=$( simple-mtpfs --list-devices -d ${DEV} 2> /dev/null )
|
||||||
|
if [ "${PHONEDEV}" = "No raw devices found." ]
|
||||||
|
then
|
||||||
|
__log "${DEV}: no raw devices found"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
PHONEDEV=$( echo "${PHONEDEV}" | awk '{print $1}' | tr -d ':' )
|
||||||
|
if [ ! ${PHONEDEV} ]
|
||||||
|
then
|
||||||
|
__log "${DEV}: no MTP devices found"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
FS_MOUNT_ARGS="--device ${PHONEDEV} ${MNT} -o allow_other -o uid=${UID} -o gid=${GID}"
|
||||||
|
;;
|
||||||
|
(*)
|
||||||
|
__log "${DEV}: filesystem not supported or no filesystem"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# create mount point
|
||||||
|
mkdir -m "${MNT_MODE}" -p "${MNT}"
|
||||||
|
__log "${DEV}: create '${MNT}' dir"
|
||||||
|
|
||||||
|
# check file system before mount
|
||||||
|
if [ -n "${FS_CHECK_CMD}" ]
|
||||||
|
then
|
||||||
|
if ! /usr/bin/which -s "${FS_CHECK_CMD}"
|
||||||
|
then
|
||||||
|
__log "command '${FS_CHECK_CMD}' not found"
|
||||||
|
__log "please install '${FS_CHECK_PORT}' port or package"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
${FS_CHECK_CMD} ${FS_CHECK_ARGS} ${DEV} \
|
||||||
|
| while read LINE
|
||||||
|
do
|
||||||
|
__log "${DEV}: ${FS_CHECK_CMD} ${LINE}"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# check is device already mounted
|
||||||
|
__check_already_mounted "${DEV}" "${MNT}"
|
||||||
|
|
||||||
|
# try to mount
|
||||||
|
if ! /usr/bin/which -s "${FS_MOUNT_CMD}"
|
||||||
|
then
|
||||||
|
__log "command '${FS_MOUNT_CMD}' not found"
|
||||||
|
__log "please install '${FS_MOUNT_PORT}' port or package"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
__wait_for_device "${DEV}"
|
||||||
|
|
||||||
|
# execute appropriate mount(8) command
|
||||||
|
COUNT=0
|
||||||
|
while ! ${FS_MOUNT_CMD} ${FS_MOUNT_ARGS} 2> /dev/null
|
||||||
|
do
|
||||||
|
if [ ! -e "${DEV}" ]
|
||||||
|
then
|
||||||
|
__log "${DEV}: device gone"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
COUNT=$(( ${COUNT} + 1 ))
|
||||||
|
if [ ${COUNT} -gt ${RETRY_COUNT} ]
|
||||||
|
then
|
||||||
|
|
||||||
|
# BEGIN | try to mount read only
|
||||||
|
FS_MOUNT_ARGS="-o ro ${FS_MOUNT_ARGS}"
|
||||||
|
${FS_MOUNT_CMD} ${FS_MOUNT_ARGS}
|
||||||
|
|
||||||
|
if [ ${?} -eq 0 ]
|
||||||
|
then
|
||||||
|
__log "${DEV}: mount OK: '${FS_MOUNT_CMD} ${FS_MOUNT_ARGS}'"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
# END | try to mount read only
|
||||||
|
|
||||||
|
__log "${DEV}: mount FAIL: '${FS_MOUNT_CMD} ${FS_MOUNT_ARGS}'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
sleep "${RETRY_DELAY}"
|
||||||
|
__log "${DEV}: filesystem mount retry: ${COUNT}/${RETRY_COUNT}"
|
||||||
|
done
|
||||||
|
__log "${DEV}: mount OK: '${FS_MOUNT_CMD} ${FS_MOUNT_ARGS}'"
|
||||||
|
|
||||||
|
# add needed rights
|
||||||
|
chown "${USER}:${MNT_GROUP}" "${MNT}"
|
||||||
|
__log "${DEV}: chown '${MNT}' dir with '${USER}:${MNT_GROUP}' rights"
|
||||||
|
|
||||||
|
# add state
|
||||||
|
PROVIDER=$( mount | grep -m 1 " ${MNT} " | awk '{printf $1}' )
|
||||||
|
__state_add ${DEV} ${PROVIDER} ${MNT}
|
||||||
|
|
||||||
|
# open file manager and display message
|
||||||
|
__show_message "Device '${DEV}' mounted on '${MNT}' directory."
|
||||||
|
if [ -n "${FM}" ]
|
||||||
|
then
|
||||||
|
GROUP_USERS=$( pw group show ${MNT_GROUP} | sed -e 's|.*:||' -e 's|,| |g' )
|
||||||
|
for I in ${GROUP_USERS}
|
||||||
|
do
|
||||||
|
[ "${I}" = "root" ] && continue
|
||||||
|
XORG_PID=$( pgrep Xorg )
|
||||||
|
[ "${XORG_PID}" = "" ] && continue
|
||||||
|
DISPLAY_ID=$( procstat pargs ${XORG_PID} | grep "^argv\[1\]:" | awk '{print $NF}' )
|
||||||
|
[ -z "${DISPLAY_ID}" ] && continue
|
||||||
|
__log "${DEV}: starting '${FM}' file manager"
|
||||||
|
su -l "${I}" -c "env DISPLAY=${DISPLAY_ID} ${FM} ${MNT} &" 1> /dev/null 2>&1
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
(detach)
|
||||||
|
__log "${DEV}: detach"
|
||||||
|
if [ -f ${STATE} ]
|
||||||
|
then
|
||||||
|
grep -E "^/dev/${1} " ${STATE} \
|
||||||
|
| while read DEV PROVIDER MNT
|
||||||
|
do
|
||||||
|
TARGET=$( mount | grep -v \.gvfs | grep -m 1 -E "^${PROVIDER} " | awk '{print $3}' )
|
||||||
|
__state_remove ${MNT}
|
||||||
|
if [ -z ${TARGET} ]
|
||||||
|
then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
( # put entire umount/find/rm block into background
|
||||||
|
# umount(8) two times to make sure its unmounted
|
||||||
|
umount -f "${TARGET}" 1> /dev/null 2>&1
|
||||||
|
umount -f "${TARGET}" 1> /dev/null 2>&1
|
||||||
|
__log "${DEV}: (state) umount '${TARGET}'"
|
||||||
|
__remove_dir "${TARGET}" &
|
||||||
|
__log "${DEV}: (state) mount point '${TARGET}' removed"
|
||||||
|
) &
|
||||||
|
unset TARGET
|
||||||
|
done
|
||||||
|
|
||||||
|
# code for NICENAMES mounting instead of the /dev/${DEV} default
|
||||||
|
if [ "${NICENAMES}" != YES ]
|
||||||
|
then
|
||||||
|
# umount(8) two times to make sure its unmounted
|
||||||
|
umount -f "${MNT_PREFIX}/${1}" 1> /dev/null 2>&1
|
||||||
|
umount -f "${MNT_PREFIX}/${1}" 1> /dev/null 2>&1
|
||||||
|
__log "${DEV}: (direct) umount '${MNT_PREFIX}/${1}'"
|
||||||
|
__remove_dir "${MNT_PREFIX}/${1}" &
|
||||||
|
__log "${DEV}: (direct) mount point '${MNT_PREFIX}/${1}' removed"
|
||||||
|
fi
|
||||||
|
__show_message "Device '${DEV}' unmounted from '${MNT}' directory."
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
esac
|
||||||
Binary file not shown.
|
|
@ -0,0 +1,3 @@
|
||||||
|
USERUMOUNT=YES
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
|
||||||
|
# PENDRIVE/PHONE/SDCARD insert
|
||||||
|
notify 100 {
|
||||||
|
match "system" "DEVFS";
|
||||||
|
match "type" "CREATE";
|
||||||
|
match "cdev" "(da|mmcsd|ugen)[0-9]+.*";
|
||||||
|
action "/usr/local/sbin/automount $cdev attach &";
|
||||||
|
};
|
||||||
|
|
||||||
|
# PENDRIVE/PHONE/SDCARD remove
|
||||||
|
notify 100 {
|
||||||
|
match "system" "DEVFS";
|
||||||
|
match "type" "DESTROY";
|
||||||
|
match "cdev" "(da|mmcsd|ugen)[0-9]+.*";
|
||||||
|
action "/usr/local/sbin/automount $cdev detach &";
|
||||||
|
};
|
||||||
|
|
||||||
|
# CD-ROM media inject
|
||||||
|
notify 100 {
|
||||||
|
match "system" "DEVFS";
|
||||||
|
match "type" "CREATE|MEDIACHANGE";
|
||||||
|
match "cdev" "(cd)[0-9]+.*";
|
||||||
|
action "/usr/local/sbin/automount $cdev attach &";
|
||||||
|
};
|
||||||
|
|
||||||
|
# CD-ROM media eject
|
||||||
|
notify 100 {
|
||||||
|
match "system" "DEVFS";
|
||||||
|
match "type" "DESTROY";
|
||||||
|
match "cdev" "(cd)[0-9]+.*";
|
||||||
|
action "/usr/local/sbin/automount $cdev detach &";
|
||||||
|
};
|
||||||
|
|
||||||
|
# CD-ROM no media
|
||||||
|
notify 100 {
|
||||||
|
match "system" "CAM";
|
||||||
|
match "subsystem" "periph";
|
||||||
|
match "type" "error";
|
||||||
|
match "cam_status" "0xcc";
|
||||||
|
match "scsi_status" "2";
|
||||||
|
match "scsi_sense" "70 02 3a 02";
|
||||||
|
match "device" "(cd)[0-9]+.*";
|
||||||
|
action "/usr/local/sbin/automount $device detach &";
|
||||||
|
};
|
||||||
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
notify 200 {
|
||||||
|
match "system" "DEVFS";
|
||||||
|
match "type" "CREATE";
|
||||||
|
match "cdev" "(da|mmcsd)[0-9]+.*";
|
||||||
|
action "/bin/sh -xe /usr/local/sbin/automount $cdev attach >> /root/DEBUG.$cdev.attach 2>&1";
|
||||||
|
};
|
||||||
|
|
||||||
|
notify 200 {
|
||||||
|
match "system" "DEVFS";
|
||||||
|
match "type" "DESTROY";
|
||||||
|
match "cdev" "(da|mmcsd)[0-9]+.*";
|
||||||
|
action "/bin/sh -xe /usr/local/sbin/automount $cdev detach >> /root/DEBUG.$cdev.detach 2>&1";
|
||||||
|
};
|
||||||
|
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
# SUPPORT md(4) IMAGES/DISKS attach
|
||||||
|
notify 100 {
|
||||||
|
match "system" "DEVFS";
|
||||||
|
match "type" "CREATE";
|
||||||
|
match "cdev" "(md)[0-9]+.*";
|
||||||
|
action "/usr/local/sbin/automount $cdev attach &";
|
||||||
|
};
|
||||||
|
|
||||||
|
# SUPPORT md(4) IMAGES/DISKS detach
|
||||||
|
notify 100 {
|
||||||
|
match "system" "DEVFS";
|
||||||
|
match "type" "DESTROY";
|
||||||
|
match "cdev" "(md)[0-9]+.*";
|
||||||
|
action "/usr/local/sbin/automount $cdev detach &";
|
||||||
|
};
|
||||||
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
|
||||||
|
# LOCAL DISKS attach
|
||||||
|
notify 100 {
|
||||||
|
match "system" "DEVFS";
|
||||||
|
match "type" "CREATE";
|
||||||
|
match "cdev" "(ada)[0-9]+.*";
|
||||||
|
action "/usr/local/sbin/automount $cdev attach &";
|
||||||
|
};
|
||||||
|
|
||||||
|
# LOCAL DISKS remove
|
||||||
|
notify 100 {
|
||||||
|
match "system" "DEVFS";
|
||||||
|
match "type" "DESTROY";
|
||||||
|
match "cdev" "(ada)[0-9]+.*";
|
||||||
|
action "/usr/local/sbin/automount $cdev detach &";
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
709
beadm
709
beadm
|
|
@ -1,709 +0,0 @@
|
||||||
#!/bin/sh -e
|
|
||||||
|
|
||||||
# Copyright (c) 2012 Slawomir Wojciech Wojtczak (vermaden). All rights reserved.
|
|
||||||
# Copyright (c) 2012 Bryan Drewery (bdrewery). All rights reserved.
|
|
||||||
# Copyright (c) 2012 Mike Clarke (rawthey). All rights reserved.
|
|
||||||
#
|
|
||||||
# Redistribution and use in source and binary forms, with or without
|
|
||||||
# modification, are permitted provided that following conditions are met:
|
|
||||||
# 1. Redistributions of source code must retain the above copyright
|
|
||||||
# notice, this list of conditions and the following disclaimer.
|
|
||||||
# 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
# notice, this list of conditions and the following disclaimer in the
|
|
||||||
# documentation and/or other materials provided with the distribution.
|
|
||||||
#
|
|
||||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS 'AS IS' AND ANY
|
|
||||||
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
|
|
||||||
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
||||||
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
unset LC_ALL
|
|
||||||
unset LANG
|
|
||||||
PATH=${PATH}:/bin:/usr/bin:/sbin:/usr/sbin
|
|
||||||
|
|
||||||
if [ $( uname -r | cut -d '.' -f1 ) -lt 8 ]
|
|
||||||
then
|
|
||||||
echo "ERROR: beadm works on FreeBSD 8.0 or later"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
__usage() {
|
|
||||||
local NAME=${0##*/}
|
|
||||||
echo "usage:"
|
|
||||||
echo " ${NAME} activate beName"
|
|
||||||
echo " ${NAME} create [-e nonActiveBe] beName"
|
|
||||||
echo " ${NAME} create [-e beName@snapshot] beName"
|
|
||||||
echo " ${NAME} create beName@snapshot"
|
|
||||||
echo " ${NAME} destroy [-F] beName"
|
|
||||||
echo " ${NAME} destroy [-F] beName@snapshot"
|
|
||||||
echo " ${NAME} list [-a]"
|
|
||||||
echo " ${NAME} list [-D]"
|
|
||||||
echo " ${NAME} mount beName [mountpoint]"
|
|
||||||
echo " ${NAME} umount [-f] beName"
|
|
||||||
echo " ${NAME} unmount [-f] beName"
|
|
||||||
echo " ${NAME} rename origBeName newBeName"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# check if boot environment exists
|
|
||||||
__be_exist() { # 1=DATASET
|
|
||||||
if ! zfs list -H -o name ${1} 1> /dev/null 2> /dev/null
|
|
||||||
then
|
|
||||||
echo "ERROR: Boot environment '${1##*/}' does not exist"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# check if argument is a snapshot
|
|
||||||
__be_snapshot() { # 1=DATASET/SNAPSHOT
|
|
||||||
echo "${1}" | grep -q "@" 2> /dev/null
|
|
||||||
}
|
|
||||||
|
|
||||||
# check if boot environment is mounted
|
|
||||||
__be_mounted() { # 1=BE
|
|
||||||
mount 2> /dev/null | grep -q -E "^${1} " 2> /dev/null
|
|
||||||
}
|
|
||||||
|
|
||||||
# check if boot environment is a clone
|
|
||||||
__be_clone() { # 1=DATASET
|
|
||||||
if zfs list ${1} 1> /dev/null 2> /dev/null
|
|
||||||
then
|
|
||||||
local ORIGIN="$( zfs list -H -o origin ${1} )"
|
|
||||||
if [ "${ORIGIN}" = "-" ]
|
|
||||||
then
|
|
||||||
# boot environment is not a clone
|
|
||||||
return 1
|
|
||||||
else
|
|
||||||
# boot environment is a clone
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
# boot environment does not exist
|
|
||||||
return 2
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# create new boot environment
|
|
||||||
__be_new() { # 1=SOURCE 2=TARGET
|
|
||||||
local SOURCE=$( echo ${1} | cut -d '@' -f 1 )
|
|
||||||
if __be_snapshot ${1}
|
|
||||||
then
|
|
||||||
# create boot environment from snapshot
|
|
||||||
local SNAPSHOT=$( echo ${1} | cut -d '@' -f 2 )
|
|
||||||
zfs list -r -H -t filesystem -o name ${SOURCE} \
|
|
||||||
| while read FS
|
|
||||||
do
|
|
||||||
if ! zfs list -H -o name ${FS}@${SNAPSHOT} 1> /dev/null 2> /dev/null
|
|
||||||
then
|
|
||||||
echo "ERROR: Child snapshot '${FS}@${SNAPSHOT}' does not exist"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
else
|
|
||||||
# create boot environment from other boot environment
|
|
||||||
if zfs list -H -o name ${1}@${2##*/} 1> /dev/null 2> /dev/null
|
|
||||||
then
|
|
||||||
echo "ERROR: Snapshot '${1}@${2##*/}' already exists"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
# snapshot format
|
|
||||||
FMT=$( date "+%Y-%m-%d-%H:%M:%S" )
|
|
||||||
if ! zfs snapshot -r ${1}@${FMT} 1> /dev/null 2> /dev/null
|
|
||||||
then
|
|
||||||
echo "ERROR: Cannot create snapshot '${1}@${FMT}'"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
# clone properties of source boot environment
|
|
||||||
zfs list -H -o name -r ${SOURCE} \
|
|
||||||
| while read FS
|
|
||||||
do
|
|
||||||
local OPTS=""
|
|
||||||
while read NAME PROPERTY VALUE
|
|
||||||
do
|
|
||||||
local OPTS="-o ${PROPERTY}=${VALUE} ${OPTS}"
|
|
||||||
done << EOF
|
|
||||||
$( zfs get -o name,property,value -s local,received -H all ${FS} | awk '!/[\t ]canmount[\t ]/' )
|
|
||||||
EOF
|
|
||||||
DATASET=$( echo ${FS} | awk '{print $1}' | sed -E s/"^${POOL}\/ROOT\/${SOURCE##*/}"/"${POOL}\/ROOT\/${2##*/}"/g )
|
|
||||||
if [ "${OPTS}" = "-o = " ]
|
|
||||||
then
|
|
||||||
local OPTS=""
|
|
||||||
fi
|
|
||||||
if __be_snapshot ${1}
|
|
||||||
then
|
|
||||||
zfs clone -o canmount=off ${OPTS} ${FS}@${1##*@} ${DATASET}
|
|
||||||
else
|
|
||||||
zfs clone -o canmount=off ${OPTS} ${FS}@${FMT} ${DATASET}
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
ROOTFS=$( mount | awk '/ \/ / {print $1}' )
|
|
||||||
|
|
||||||
if echo ${ROOTFS} | grep -q -m 1 -E "^/dev/"
|
|
||||||
then
|
|
||||||
echo "ERROR: This system does not boot from ZFS pool"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
POOL=$( echo ${ROOTFS} | awk -F '/' '{print $1}' )
|
|
||||||
|
|
||||||
if ! zfs list ${POOL}/ROOT 1> /dev/null 2> /dev/null
|
|
||||||
then
|
|
||||||
echo "ERROR: This system is not configured for boot environments"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
BOOTFS=$( zpool list -H -o bootfs ${POOL} )
|
|
||||||
|
|
||||||
if [ -z "${BOOTFS}" -o "${BOOTFS}" = "-" ]
|
|
||||||
then
|
|
||||||
echo "ERROR: ZFS boot pool '${POOL}' has unset 'bootfs' property"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
case ${1} in
|
|
||||||
|
|
||||||
(list) # --------------------------------------------------------------------
|
|
||||||
OPTION_a=0
|
|
||||||
OPTION_D=0
|
|
||||||
shift
|
|
||||||
while getopts "aD" OPT
|
|
||||||
do
|
|
||||||
case ${OPT} in
|
|
||||||
(a) OPTION_a=1 ;;
|
|
||||||
(D) OPTION_D=1 ;;
|
|
||||||
(*) __usage ;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
awk -v POOL="${POOL}" \
|
|
||||||
-v ROOTFS="${ROOTFS}" \
|
|
||||||
-v BOOTFS="${BOOTFS}" \
|
|
||||||
-v OPTION_a="${OPTION_a}" \
|
|
||||||
-v OPTION_D="${OPTION_D}" \
|
|
||||||
'function __normalize(VALUE) {
|
|
||||||
return substr(VALUE, 1, length(VALUE) - 1) * MULTIPLIER[substr(VALUE, length(VALUE))]
|
|
||||||
}
|
|
||||||
function __show_units(VALUE) {
|
|
||||||
if(VALUE < 1025) { UNIT = "K"; }
|
|
||||||
else if(VALUE < 1048576) { VALUE /= 1024; UNIT = "M"; }
|
|
||||||
else if(VALUE < 1073741824) { VALUE /= 1048576; UNIT = "G"; }
|
|
||||||
else if(VALUE < 1099511627776) { VALUE /= 1073741824; UNIT = "T"; }
|
|
||||||
else if(VALUE < 1125899906842624) { VALUE /= 1099511627776; UNIT = "P"; }
|
|
||||||
else if(VALUE < 1152921504606846976) { VALUE /= 1125899906842624; UNIT = "E"; }
|
|
||||||
else { VALUE /= 1152921504606846976; UNIT = "Z"; }
|
|
||||||
return sprintf("%.1f%s", VALUE, UNIT)
|
|
||||||
}
|
|
||||||
function __get_bename(BENAME) {
|
|
||||||
sub(BENAME_BEGINS_WITH "\/", "", BENAME)
|
|
||||||
sub("/.*", "", BENAME)
|
|
||||||
return BENAME
|
|
||||||
}
|
|
||||||
function __convert_date(DATE) {
|
|
||||||
"date -j -f \"%a %b %d %H:%M %Y\" \"" DATE "\" +\"%Y-%m-%d %H:%M\"" | getline NEW
|
|
||||||
close("date -j -f \"%a %b %d %H:%M %Y\" \"" DATE "\" +\"%Y-%m-%d %H:%M\"")
|
|
||||||
return NEW
|
|
||||||
}
|
|
||||||
BEGIN {
|
|
||||||
FS = "\\t"
|
|
||||||
BENAME_BEGINS_WITH = POOL "/ROOT"
|
|
||||||
MULTIPLIER["K"] = 1
|
|
||||||
MULTIPLIER["M"] = 1024
|
|
||||||
MULTIPLIER["G"] = 1048576
|
|
||||||
MULTIPLIER["T"] = 1073741824
|
|
||||||
MULTIPLIER["P"] = 1099511627776
|
|
||||||
MULTIPLIER["E"] = 1125899906842624
|
|
||||||
MULTIPLIER["Z"] = 1152921504606846976
|
|
||||||
MOUNTPOINT_LENGTH = 10
|
|
||||||
FSNAME_LENGTH = 2
|
|
||||||
if(OPTION_a == 1)
|
|
||||||
FSNAME_LENGTH = 19
|
|
||||||
while("zfs list -H -t all -s creation -o name,used,usedds,usedbysnapshots,usedrefreserv,refer,creation,origin -r " BENAME_BEGINS_WITH | getline) {
|
|
||||||
FSNAME = $1
|
|
||||||
FSNAMES[length(FSNAMES) + 1] = FSNAME
|
|
||||||
if(FSNAME != BENAME_BEGINS_WITH) {
|
|
||||||
if(FSNAME ~ "@")
|
|
||||||
SPACES[FSNAME] = __normalize($2) + __normalize($5)
|
|
||||||
else {
|
|
||||||
SPACES[FSNAME] = __normalize($3) + __normalize($5)
|
|
||||||
BE = " " __get_bename(FSNAME) " "
|
|
||||||
if(index(BELIST, BE) == 0)
|
|
||||||
BELIST = BELIST " " BE
|
|
||||||
}
|
|
||||||
USEDBYSNAPSHOTS = $4
|
|
||||||
USEDREFRESERV[FSNAME] = __normalize($5)
|
|
||||||
REFER[FSNAME] = __normalize($6)
|
|
||||||
CREATIONS[FSNAME] = $7
|
|
||||||
ORIGINS[FSNAME] = $8
|
|
||||||
if(USEDBYSNAPSHOTS != 0 && USEDBYSNAPSHOTS != "-")
|
|
||||||
SPACES[FSNAME] += __normalize(USEDBYSNAPSHOTS)
|
|
||||||
MOUNTLINE = ""
|
|
||||||
"mount | grep \"^" FSNAME " \"" | getline MOUNTLINE
|
|
||||||
split(MOUNTLINE, MOUNTDATA, " ")
|
|
||||||
MOUNTPOINT = MOUNTDATA[3]
|
|
||||||
if(MOUNTPOINT == "")
|
|
||||||
MOUNTPOINT = "-"
|
|
||||||
MOUNTS[FSNAME] = MOUNTPOINT
|
|
||||||
LM = length(MOUNTPOINT)
|
|
||||||
if((OPTION_a == 0 && FSNAME == (BENAME_BEGINS_WITH "/" __get_bename(FSNAME))) || (OPTION_a == 1 && FSNAME !~ /@/)) {
|
|
||||||
if(LM > MOUNTPOINT_LENGTH)
|
|
||||||
MOUNTPOINT_LENGTH = LM
|
|
||||||
}
|
|
||||||
if(OPTION_a == 1)
|
|
||||||
LF = length(FSNAME)
|
|
||||||
else if(FSNAME !~ /@/)
|
|
||||||
LF = length(__get_bename(FSNAME))
|
|
||||||
if(LF > FSNAME_LENGTH)
|
|
||||||
FSNAME_LENGTH = LF
|
|
||||||
}
|
|
||||||
}
|
|
||||||
split(BELIST, BENAMES, " ")
|
|
||||||
if(OPTION_a == 1) {
|
|
||||||
BE_HEAD = "BE/Dataset/Snapshot"
|
|
||||||
FSNAME_LENGTH += 2
|
|
||||||
}
|
|
||||||
else
|
|
||||||
BE_HEAD = "BE"
|
|
||||||
printf "%-" FSNAME_LENGTH "s %-6s %-" MOUNTPOINT_LENGTH "s %6s %s\n", BE_HEAD, "Active", "Mountpoint", "Space", "Created"
|
|
||||||
for(I = 1; I <= length(BENAMES); I++) {
|
|
||||||
BENAME = BENAMES[I]
|
|
||||||
if(OPTION_a == 1) {
|
|
||||||
print BENAME
|
|
||||||
for(J = 1; J <= length(FSNAMES); J++) {
|
|
||||||
FSNAME = FSNAMES[J]
|
|
||||||
if(FSNAME ~ "^" BENAME_BEGINS_WITH "/" BENAME "(/[^@]*)?$") {
|
|
||||||
ACTIVE = ""
|
|
||||||
if(FSNAME == ROOTFS)
|
|
||||||
ACTIVE = ACTIVE "N"
|
|
||||||
if(FSNAME == BOOTFS)
|
|
||||||
ACTIVE = ACTIVE "R"
|
|
||||||
if(! ACTIVE)
|
|
||||||
ACTIVE = "-"
|
|
||||||
printf " %-" FSNAME_LENGTH "s %-6s %-" MOUNTPOINT_LENGTH "s %6s %s\n", FSNAME, ACTIVE, MOUNTS[FSNAME], __show_units(SPACES[FSNAME]), __convert_date(CREATIONS[FSNAME])
|
|
||||||
ORIGIN = ORIGINS[FSNAME]
|
|
||||||
if(ORIGIN != "-") {
|
|
||||||
if(OPTION_D == 1)
|
|
||||||
SPACE = REFER[ORIGIN]
|
|
||||||
else
|
|
||||||
SPACE = SPACES[ORIGIN]
|
|
||||||
printf " %-" FSNAME_LENGTH "s %-6s %-" MOUNTPOINT_LENGTH "s %6s %s\n", ORIGIN, "-", MOUNTS[ORIGIN], __show_units(SPACE), __convert_date(CREATIONS[ORIGIN])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
SPACE = 0
|
|
||||||
ACTIVE = ""
|
|
||||||
NAME = BENAME_BEGINS_WITH "/" BENAME
|
|
||||||
if(NAME == ROOTFS)
|
|
||||||
ACTIVE = ACTIVE "N"
|
|
||||||
if(NAME == BOOTFS)
|
|
||||||
ACTIVE = ACTIVE "R"
|
|
||||||
if(! ACTIVE)
|
|
||||||
ACTIVE = "-"
|
|
||||||
for(J = 1; J <= length(FSNAMES); J++) {
|
|
||||||
FSNAME = FSNAMES[J]
|
|
||||||
if(FSNAME ~ "^" BENAME_BEGINS_WITH "/" BENAME "(/[^@]*)?$") {
|
|
||||||
if((BENAME_BEGINS_WITH "/" BENAME) == FSNAME) {
|
|
||||||
MOUNTPOINT = MOUNTS[FSNAME]
|
|
||||||
CREATION = __convert_date(CREATIONS[FSNAME])
|
|
||||||
}
|
|
||||||
SPACE += SPACES[FSNAME]
|
|
||||||
ORIGIN = ORIGINS[FSNAME]
|
|
||||||
if(ORIGIN != "-") {
|
|
||||||
if(OPTION_D == 1)
|
|
||||||
SPACE += REFER[ORIGIN]
|
|
||||||
else
|
|
||||||
SPACE += SPACES[ORIGIN]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf "%-" FSNAME_LENGTH "s %-6s %-" MOUNTPOINT_LENGTH "s %6s %s\n", BENAME, ACTIVE, MOUNTPOINT, __show_units(SPACE), CREATION
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}'
|
|
||||||
;;
|
|
||||||
|
|
||||||
(create) # ------------------------------------------------------------------
|
|
||||||
case ${#} in
|
|
||||||
(4)
|
|
||||||
if ! [ ${2} = "-e" ]
|
|
||||||
then
|
|
||||||
__usage
|
|
||||||
fi
|
|
||||||
# check if argument for -e option is full path dataset
|
|
||||||
# argument for -e option must be 'beName' or 'beName@snapshot'
|
|
||||||
if echo ${3} | grep -q "/" 2> /dev/null
|
|
||||||
then
|
|
||||||
__usage
|
|
||||||
fi
|
|
||||||
__be_exist ${POOL}/ROOT/${3}
|
|
||||||
if zfs list -H -o name ${POOL}/ROOT/${4} 1> /dev/null 2> /dev/null
|
|
||||||
then
|
|
||||||
echo "ERROR: Boot environment '${4}' already exists"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
__be_new ${POOL}/ROOT/${3} ${POOL}/ROOT/${4}
|
|
||||||
;;
|
|
||||||
(2)
|
|
||||||
if __be_snapshot ${2}
|
|
||||||
then
|
|
||||||
if ! zfs snapshot -r ${POOL}/ROOT/${2} 1> /dev/null 2> /dev/null
|
|
||||||
then
|
|
||||||
echo "ERROR: Cannot create '${2}' recursive snapshot"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
__be_new ${ROOTFS} ${POOL}/ROOT/${2}
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
(*)
|
|
||||||
__usage
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
echo "Created successfully"
|
|
||||||
;;
|
|
||||||
|
|
||||||
(activate) # ----------------------------------------------------------------
|
|
||||||
if [ ${#} -ne 2 ]
|
|
||||||
then
|
|
||||||
__usage
|
|
||||||
fi
|
|
||||||
__be_exist ${POOL}/ROOT/${2}
|
|
||||||
if [ "${BOOTFS}" = "${POOL}/ROOT/${2}" ]
|
|
||||||
then
|
|
||||||
echo "Already activated"
|
|
||||||
exit 0
|
|
||||||
else
|
|
||||||
if __be_mounted ${POOL}/ROOT/${2}
|
|
||||||
then
|
|
||||||
MNT=$( mount | grep -E "^${POOL}/ROOT/${2} " | awk '{print $3}' )
|
|
||||||
if [ "${MNT}" != "/" ]
|
|
||||||
then
|
|
||||||
# boot environment is not current root and its mounted
|
|
||||||
echo "ERROR: Boot environment '${2}' is mounted at '${MNT}'"
|
|
||||||
echo "ERROR: Cannot activate manually mounted boot environment"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
# do not change root (/) mounted boot environment mountpoint
|
|
||||||
if [ "${ROOTFS}" != "${POOL}/ROOT/${2}" ]
|
|
||||||
then
|
|
||||||
TMPMNT=$( mktemp -d /tmp/tmp.XXXXXX )
|
|
||||||
if ! mkdir -p ${TMPMNT} 2> /dev/null
|
|
||||||
then
|
|
||||||
echo "ERROR: Cannot create '${TMPMNT}' directory"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
MOUNT=0
|
|
||||||
while read FS MNT TYPE OPTS DUMP FSCK;
|
|
||||||
do
|
|
||||||
if [ "${FS}" = "${POOL}/ROOT/${2}" ]
|
|
||||||
then
|
|
||||||
MOUNT=${MNT}
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done << EOF
|
|
||||||
$( mount -p )
|
|
||||||
EOF
|
|
||||||
if [ ${MOUNT} -eq 0 ]
|
|
||||||
then
|
|
||||||
zfs set canmount=noauto ${POOL}/ROOT/${2}
|
|
||||||
zfs set mountpoint=${TMPMNT} ${POOL}/ROOT/${2}
|
|
||||||
zfs mount ${POOL}/ROOT/${2}
|
|
||||||
else
|
|
||||||
TMPMNT=${MOUNT}
|
|
||||||
fi
|
|
||||||
cp /boot/zfs/zpool.cache ${TMPMNT}/boot/zfs/zpool.cache
|
|
||||||
LOADER_CONFIGS=${TMPMNT}/boot/loader.conf
|
|
||||||
if [ -f ${TMPMNT}/boot/loader.conf.local ]
|
|
||||||
then
|
|
||||||
LOADER_CONFIGS="${LOADER_CONFIGS} ${TMPMNT}/boot/loader.conf.local"
|
|
||||||
fi
|
|
||||||
sed -i '' -E s/"^vfs.root.mountfrom=.*$"/"vfs.root.mountfrom=\"zfs:${POOL}\/ROOT\/${2##*/}\""/g ${LOADER_CONFIGS}
|
|
||||||
if [ ${MOUNT} -eq 0 ]
|
|
||||||
then
|
|
||||||
zfs umount ${POOL}/ROOT/${2}
|
|
||||||
zfs set mountpoint=legacy ${POOL}/ROOT/${2}
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
if ! zpool set bootfs=${POOL}/ROOT/${2} ${POOL} 1> /dev/null 2> /dev/null
|
|
||||||
then
|
|
||||||
echo "ERROR: Failed to activate '${2}' boot environment"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
# execute ZFS LIST only once
|
|
||||||
ZFS_LIST=$( zfs list -H -o name -r ${POOL}/ROOT )
|
|
||||||
# disable automatic mount on all inactive boot environments
|
|
||||||
echo "${ZFS_LIST}" \
|
|
||||||
| grep -v "^${POOL}/ROOT/${2}" \
|
|
||||||
| while read NAME
|
|
||||||
do
|
|
||||||
zfs set canmount=noauto ${NAME}
|
|
||||||
done
|
|
||||||
# enable automatic mount for active boot environment and promote it
|
|
||||||
echo "${ZFS_LIST}" \
|
|
||||||
| grep "^${POOL}/ROOT/${2}" \
|
|
||||||
| while read NAME
|
|
||||||
do
|
|
||||||
zfs set canmount=on ${NAME}
|
|
||||||
while __be_clone ${NAME}
|
|
||||||
do
|
|
||||||
zfs promote ${NAME}
|
|
||||||
done
|
|
||||||
done
|
|
||||||
echo "Activated successfully"
|
|
||||||
;;
|
|
||||||
|
|
||||||
(destroy) # -----------------------------------------------------------------
|
|
||||||
if [ "${2}" != "-F" ]
|
|
||||||
then
|
|
||||||
DESTROY=${2}
|
|
||||||
else
|
|
||||||
DESTROY=${3}
|
|
||||||
fi
|
|
||||||
__be_exist ${POOL}/ROOT/${DESTROY}
|
|
||||||
case ${#} in
|
|
||||||
(2)
|
|
||||||
echo "Are you sure you want to destroy '${2}'?"
|
|
||||||
echo -n "This action cannot be undone (y/[n]): "
|
|
||||||
read CHOICE
|
|
||||||
;;
|
|
||||||
(3)
|
|
||||||
if [ "${2}" != "-F" ]
|
|
||||||
then
|
|
||||||
__usage
|
|
||||||
fi
|
|
||||||
CHOICE=Y
|
|
||||||
;;
|
|
||||||
(*)
|
|
||||||
__usage
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
if [ "${BOOTFS}" = "${POOL}/ROOT/${DESTROY}" ]
|
|
||||||
then
|
|
||||||
echo "ERROR: Cannot destroy active boot environment"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
case ${CHOICE} in
|
|
||||||
(Y|y|[Yy][Ee][Ss])
|
|
||||||
# destroy snapshot or boot environment
|
|
||||||
if __be_snapshot ${POOL}/ROOT/${DESTROY}
|
|
||||||
then
|
|
||||||
# destroy desired snapshot
|
|
||||||
if ! zfs destroy -r ${POOL}/ROOT/${DESTROY} 1> /dev/null 2> /dev/null
|
|
||||||
then
|
|
||||||
echo "ERROR: Snapshot '${2}' is origin for other boot environment"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
if __be_clone ${POOL}/ROOT/${DESTROY}
|
|
||||||
then
|
|
||||||
# promote clones dependent on snapshots used by destroyed boot environment
|
|
||||||
zfs list -H -t all -o name,origin \
|
|
||||||
| while read NAME ORIGIN
|
|
||||||
do
|
|
||||||
if echo "${ORIGIN}" | grep -q -E "${POOL}/ROOT/${DESTROY}(/.*@|@)" 2> /dev/null
|
|
||||||
then
|
|
||||||
zfs promote ${NAME}
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
# get origins used by destroyed boot environment
|
|
||||||
ORIGIN_SNAPSHOTS=$( zfs list -H -t all -o origin -r ${POOL}/ROOT/${DESTROY} | grep -v '^-$' | awk -F "@" '{print $2}' | sort -u )
|
|
||||||
fi
|
|
||||||
# check if boot environment was created from existing snapshot
|
|
||||||
ORIGIN=$( zfs list -H -o origin ${POOL}/ROOT/${DESTROY} )
|
|
||||||
CREATION=$( zfs list -H -o creation ${POOL}/ROOT/${DESTROY} )
|
|
||||||
CREATION=$( date -j -f "%a %b %d %H:%M %Y" "${CREATION}" +"%Y-%m-%d-%H:%M" )
|
|
||||||
SNAPSHOT_NAME=$( echo "${ORIGIN}" | cut -d '@' -f 2 | sed -E 's/:[0-9]{2}$//g' )
|
|
||||||
if [ "${2}" = "-F" ]
|
|
||||||
then
|
|
||||||
CHOICE=1
|
|
||||||
elif [ "${SNAPSHOT_NAME}" != "${CREATION}" ]
|
|
||||||
then
|
|
||||||
ORIGIN=$( basename ${ORIGIN} )
|
|
||||||
echo "Boot environment '${DESTROY}' was created from existing snapshot"
|
|
||||||
echo -n "Destroy '${ORIGIN}' snapshot? (y/[n]): "
|
|
||||||
read CHOICE
|
|
||||||
case ${CHOICE} in
|
|
||||||
(Y|y|[Yy][Ee][Ss])
|
|
||||||
CHOICE=1
|
|
||||||
;;
|
|
||||||
(*)
|
|
||||||
CHOICE=0
|
|
||||||
echo "Origin snapshot '${ORIGIN}' will be preserved"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
else
|
|
||||||
CHOICE=1
|
|
||||||
fi
|
|
||||||
# destroy boot environment
|
|
||||||
zfs destroy -r ${POOL}/ROOT/${DESTROY}
|
|
||||||
# check if boot environment is a clone
|
|
||||||
if __be_clone ${POOL}/ROOT/${DESTROY}
|
|
||||||
then
|
|
||||||
# promote datasets dependent on origins used by destroyed boot environment
|
|
||||||
ALL_ORIGINS=$( zfs list -H -t all -o name,origin )
|
|
||||||
echo "${ORIGIN_SNAPSHOTS}" \
|
|
||||||
| while read S
|
|
||||||
do
|
|
||||||
echo "${ALL_ORIGINS}" \
|
|
||||||
| grep "${S}" \
|
|
||||||
| awk '{print $1}' \
|
|
||||||
| while read I
|
|
||||||
do
|
|
||||||
zfs promote ${I}
|
|
||||||
done
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
# destroy origins used by destroyed boot environment
|
|
||||||
SNAPSHOTS=$( zfs list -H -t snapshot -o name )
|
|
||||||
echo "${ORIGIN_SNAPSHOTS}" \
|
|
||||||
| while read S
|
|
||||||
do
|
|
||||||
echo "${SNAPSHOTS}" \
|
|
||||||
| grep "@${S}$" \
|
|
||||||
| while read I
|
|
||||||
do
|
|
||||||
if [ ${CHOICE} -eq 1 ]
|
|
||||||
then
|
|
||||||
zfs destroy ${I}
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
echo "Destroyed successfully"
|
|
||||||
;;
|
|
||||||
(*)
|
|
||||||
echo "Boot environment '${DESTROY}' has not been destroyed"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
;;
|
|
||||||
|
|
||||||
(rename) # ------------------------------------------------------------------
|
|
||||||
if [ ${#} -ne 3 ]
|
|
||||||
then
|
|
||||||
__usage
|
|
||||||
fi
|
|
||||||
__be_exist ${POOL}/ROOT/${2}
|
|
||||||
if [ "${BOOTFS}" = "${POOL}/ROOT/${2}" ]
|
|
||||||
then
|
|
||||||
echo "ERROR: Renaming active boot environment is not supported"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if zfs list -H -o name ${POOL}/ROOT/${3} 2> /dev/null
|
|
||||||
then
|
|
||||||
echo "ERROR: Boot environment '${3}' already exists"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
zfs rename ${POOL}/ROOT/${2} ${POOL}/ROOT/${3}
|
|
||||||
echo "Renamed successfully"
|
|
||||||
;;
|
|
||||||
|
|
||||||
(mount) # -------------------------------------------------------------------
|
|
||||||
if [ ${#} -eq 2 ]
|
|
||||||
then
|
|
||||||
TARGET=$( mktemp -d /tmp/tmp.XXXXXX )
|
|
||||||
elif [ ${#} -eq 3 ]
|
|
||||||
then
|
|
||||||
TARGET=${3}
|
|
||||||
else
|
|
||||||
__usage
|
|
||||||
fi
|
|
||||||
__be_exist "${POOL}/ROOT/${2}"
|
|
||||||
if __be_mounted "${POOL}/ROOT/${2}"
|
|
||||||
then
|
|
||||||
MNT=$( mount | grep -E "^${POOL}/ROOT/${2} " | awk '{print $3}' )
|
|
||||||
echo "Boot environment '${2}' is already mounted at '${MNT}'"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if ! mkdir -p ${TARGET} 2> /dev/null
|
|
||||||
then
|
|
||||||
echo "ERROR: Cannot create '${TARGET}' mountpoint"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if ! mount -t zfs ${POOL}/ROOT/${2} ${TARGET}
|
|
||||||
then
|
|
||||||
echo "ERROR: Cannot mount '${2}' at '${TARGET}' mountpoint"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
PREFIX=$( echo ${POOL}/ROOT/${2}/ | sed 's/\//\\\//g' )
|
|
||||||
zfs list -H -o name,mountpoint -r ${POOL}/ROOT/${2} \
|
|
||||||
| grep -v "legacy$" \
|
|
||||||
| sort -n \
|
|
||||||
| grep -E "^${POOL}/ROOT/${2}/" \
|
|
||||||
| while read FS MOUNTPOINT
|
|
||||||
do
|
|
||||||
if [ "{FS}" != "${POOL}/ROOT/${2}" ]
|
|
||||||
then
|
|
||||||
INHERIT=$( zfs get -H -o source mountpoint ${FS} )
|
|
||||||
if [ "${INHERIT}" = "local" ]
|
|
||||||
then
|
|
||||||
if [ "${MOUNTPOINT}" = "legacy" ]
|
|
||||||
then
|
|
||||||
continue
|
|
||||||
else
|
|
||||||
MOUNTPOINT="/$( echo "${FS}" | sed s/"${PREFIX}"//g )"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
if ! mkdir -p ${TARGET}${MOUNTPOINT} 1> /dev/null 2> /dev/null
|
|
||||||
then
|
|
||||||
echo "ERROR: Cannot create '${TARGET}${MOUNTPOINT}' mountpoint"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if ! mount -t zfs ${FS} ${TARGET}${MOUNTPOINT} 1> /dev/null 2> /dev/null
|
|
||||||
then
|
|
||||||
echo "ERROR: Cannot mount '${FS}' at '${TARGET}${MOUNTPOINT}' mountpoint"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
echo "Mounted successfully on '${TARGET}'"
|
|
||||||
;;
|
|
||||||
|
|
||||||
(umount|unmount) # ----------------------------------------------------------
|
|
||||||
if [ ${#} -eq 2 ]
|
|
||||||
then
|
|
||||||
# we need this empty section for argument checking
|
|
||||||
:
|
|
||||||
elif [ ${#} -eq 3 -a "${2}" = "-f" ]
|
|
||||||
then
|
|
||||||
OPTS="-f"
|
|
||||||
shift
|
|
||||||
else
|
|
||||||
__usage
|
|
||||||
fi
|
|
||||||
__be_exist "${POOL}/ROOT/${2}"
|
|
||||||
if ! __be_mounted "${POOL}/ROOT/${2}"
|
|
||||||
then
|
|
||||||
echo "Boot environment '${2}' is not mounted"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
mount \
|
|
||||||
| grep "^${POOL}/ROOT/${2}" \
|
|
||||||
| awk '{print $1}' \
|
|
||||||
| sort -n -r \
|
|
||||||
| while read FS
|
|
||||||
do
|
|
||||||
if ! umount ${OPTS} ${FS} 1> /dev/null 2> /dev/null
|
|
||||||
then
|
|
||||||
echo "ERROR: Cannot umount '${FS}' dataset"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
echo "Unmounted successfully"
|
|
||||||
;;
|
|
||||||
|
|
||||||
(*) # -----------------------------------------------------------------------
|
|
||||||
__usage
|
|
||||||
;;
|
|
||||||
|
|
||||||
esac
|
|
||||||
184
beadm.1
184
beadm.1
|
|
@ -1,184 +0,0 @@
|
||||||
.\"
|
|
||||||
.\" beadm - Illumos/Solaris-like utility for FreeBSD to manage
|
|
||||||
.\" Boot Environments on ZFS filesystems
|
|
||||||
.\"
|
|
||||||
.\" Redistribution and use in source and binary forms, with or without
|
|
||||||
.\" modification, are permitted provided that the following conditions
|
|
||||||
.\" are met:
|
|
||||||
.\" 1. Redistributions of source code must retain the above copyright
|
|
||||||
.\" notice, this list of conditions and the following disclaimer.
|
|
||||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
.\" notice, this list of conditions and the following disclaimer in the
|
|
||||||
.\" documentation and/or other materials provided with the distribution.
|
|
||||||
.\"
|
|
||||||
.\"
|
|
||||||
.\" @(#)beadm.1
|
|
||||||
.\" $FreeBSD$
|
|
||||||
.\"
|
|
||||||
.Dd September 4, 2012
|
|
||||||
.Dt BEADM 1
|
|
||||||
.Os FreeBSD
|
|
||||||
.Sh NAME
|
|
||||||
.Nm beadm
|
|
||||||
.Nd Utility to manage Boot Environments with ZFS
|
|
||||||
.Sh SYNOPSIS
|
|
||||||
.Nm
|
|
||||||
activate
|
|
||||||
.Ao Ar beName Ac
|
|
||||||
.Nm
|
|
||||||
create
|
|
||||||
.Op Fl e Ar nonActiveBe | Fl e Ar beName@snapshot
|
|
||||||
.Ao Ar beName Ac
|
|
||||||
.Nm
|
|
||||||
create
|
|
||||||
.Ao Ar beName@snapshot Ac
|
|
||||||
.Nm
|
|
||||||
destroy
|
|
||||||
.Op Fl F
|
|
||||||
.Ao Ar beName | beName@snapshot Ac
|
|
||||||
.Nm
|
|
||||||
list
|
|
||||||
.Op Fl a | Fl D
|
|
||||||
.Nm
|
|
||||||
mount
|
|
||||||
.Ao Ar beName Ac
|
|
||||||
.Op mountpoint
|
|
||||||
.Nm
|
|
||||||
rename
|
|
||||||
.Ao Ar origBeName Ac
|
|
||||||
.Ao Ar newBeName Ac
|
|
||||||
.Nm
|
|
||||||
{ umount | unmount }
|
|
||||||
.Op Fl f
|
|
||||||
.Ao Ar beName Ac
|
|
||||||
.Sh DESCRIPTION
|
|
||||||
The
|
|
||||||
.Nm
|
|
||||||
command is used to setup and interact with Boot Environments with ZFS.
|
|
||||||
.Pp
|
|
||||||
.Em Boot Environments
|
|
||||||
allows the system to be upgraded, while preserving the old system environment in a separate ZFS dataset.
|
|
||||||
.Pp
|
|
||||||
.Sh COMMANDS
|
|
||||||
The following commands are supported by
|
|
||||||
.Nm :
|
|
||||||
.Bl -tag -width indent
|
|
||||||
.It Ic activate Ar <beName>
|
|
||||||
.Pp
|
|
||||||
Activate the given
|
|
||||||
.Ar beName
|
|
||||||
for the next boot.
|
|
||||||
.Pp
|
|
||||||
.It Ic create
|
|
||||||
.Op Fl e Ar nonActiveBe | Fl e Ar beName@snapshot
|
|
||||||
.Ao Ar beName Ac
|
|
||||||
.Pp
|
|
||||||
Creates a new boot environment named
|
|
||||||
.Ar beName .
|
|
||||||
If the -e param is specified, the new environment will be cloned from the given
|
|
||||||
.Ar nonActiveBe | Ar beName@snapshot .
|
|
||||||
.Pp
|
|
||||||
.It Ic create
|
|
||||||
.Ao Ar beName@snapshot Ac
|
|
||||||
.Pp
|
|
||||||
Creates a snapshot of the existing boot environment named
|
|
||||||
.Ar beName .
|
|
||||||
.Pp
|
|
||||||
.It
|
|
||||||
.Ic destroy Op Fl F
|
|
||||||
.Ao Ar beName | beName@snapshot Ac
|
|
||||||
.Pp
|
|
||||||
Destroys the given
|
|
||||||
.Ar beName
|
|
||||||
boot environment or
|
|
||||||
.Ar beName@snapshot
|
|
||||||
snapshot.
|
|
||||||
Specifying
|
|
||||||
.Fl F
|
|
||||||
will automatically unmount without confirmation.
|
|
||||||
.Pp
|
|
||||||
.It Ic list
|
|
||||||
.Op Fl a | Fl D
|
|
||||||
.Pp
|
|
||||||
Displays all boot environments.
|
|
||||||
.PP
|
|
||||||
If
|
|
||||||
.Fl a
|
|
||||||
is used, display all datasets and snapshots as well.
|
|
||||||
If
|
|
||||||
.Fl D
|
|
||||||
is used, display the full space usage for each boot environment, assuming all other boot environments were destroyed.
|
|
||||||
.Pp
|
|
||||||
.It Ic mount
|
|
||||||
.Ao Ar beName Ac
|
|
||||||
.Op mountpoint
|
|
||||||
.Pp
|
|
||||||
Temporarily mount the boot environment.
|
|
||||||
Mount at the specified
|
|
||||||
.Ar mountpoint
|
|
||||||
if provided.
|
|
||||||
.Pp
|
|
||||||
.It Ic rename Ao Ar origBeName Ac Ao Ar newBeName Ac
|
|
||||||
.Pp
|
|
||||||
Renames the given nonactive
|
|
||||||
.Ar origBeName
|
|
||||||
to the given
|
|
||||||
.Ar newBeName
|
|
||||||
.Pp
|
|
||||||
.It Ic umount
|
|
||||||
.Op Fl f
|
|
||||||
.Ao Ar beName Ac
|
|
||||||
.Pp
|
|
||||||
Unmount the given boot environment, if it is mounted.
|
|
||||||
Specifying
|
|
||||||
.Fl f
|
|
||||||
will force the unmount if busy.
|
|
||||||
.Pp
|
|
||||||
.El
|
|
||||||
.Sh EXAMPLES
|
|
||||||
.Bl -bullet
|
|
||||||
.It
|
|
||||||
Perform a system upgrade in a
|
|
||||||
.Xr jail 8
|
|
||||||
.Pp
|
|
||||||
Create a new boot environment called
|
|
||||||
.Em jailed :
|
|
||||||
.Pp
|
|
||||||
.Dl beadm create -e default jailed
|
|
||||||
.Pp
|
|
||||||
Set mountpoint for new jail to
|
|
||||||
.Pa /usr/jails/jailed :
|
|
||||||
.Pp
|
|
||||||
.Dl beadm mount jailed /usr/jails/jailed
|
|
||||||
.Pp
|
|
||||||
The currently active boot environment is now replicated into the jailed system and ready for upgrade.
|
|
||||||
Startup the jail, login and perform the normal upgrade process.
|
|
||||||
Once this is done, stop the jail and disable it in
|
|
||||||
.Pa /etc/rc.conf.
|
|
||||||
.Pp
|
|
||||||
Now activate the boot environment for the next boot
|
|
||||||
.Pp
|
|
||||||
.Dl beadmn activate jailed
|
|
||||||
.Pp
|
|
||||||
Reboot into the new environment
|
|
||||||
.Pp
|
|
||||||
.Dl reboot
|
|
||||||
.El
|
|
||||||
.Sh HOWTO
|
|
||||||
A HOWTO guide is posted at the FreeBSD forums:
|
|
||||||
.Bl -bullet
|
|
||||||
.It
|
|
||||||
.Ar http://forums.freebsd.org/showthread.php?t=31662
|
|
||||||
.El
|
|
||||||
.Pp
|
|
||||||
.Sh SEE ALSO
|
|
||||||
.Xr jail 8 ,
|
|
||||||
.Xr zfs 8 ,
|
|
||||||
.Xr zpool 8
|
|
||||||
.Sh HISTORY
|
|
||||||
.Xr beadm 1M
|
|
||||||
originally appeared in Solaris.
|
|
||||||
.Sh AUTHORS
|
|
||||||
.An Slawomir Wojciech Wojtczak (vermaden) Aq vermaden@interia.pl
|
|
||||||
.An Bryan Drewery Aq bryan@shatow.net
|
|
||||||
wrote this manual page and contributed child dataset fixes
|
|
||||||
Loading…
Reference in New Issue