summaryrefslogtreecommitdiff
path: root/package/aufs2-util/src
diff options
context:
space:
mode:
Diffstat (limited to 'package/aufs2-util/src')
-rw-r--r--package/aufs2-util/src/COPYING340
-rw-r--r--package/aufs2-util/src/Makefile103
-rw-r--r--package/aufs2-util/src/README46
-rw-r--r--package/aufs2-util/src/au_util.h67
-rwxr-xr-xpackage/aufs2-util/src/aubrsync304
-rwxr-xr-xpackage/aufs2-util/src/auchk130
-rw-r--r--package/aufs2-util/src/aufs.in.51684
-rw-r--r--package/aufs2-util/src/aufs.shlib83
-rw-r--r--package/aufs2-util/src/auplink.c64
-rw-r--r--package/aufs2-util/src/br.c172
-rw-r--r--package/aufs2-util/src/c2sh.c42
-rw-r--r--package/aufs2-util/src/c2tmac.c44
-rw-r--r--package/aufs2-util/src/compat.h34
-rw-r--r--package/aufs2-util/src/mount.aufs.c255
-rw-r--r--package/aufs2-util/src/mtab.c216
-rw-r--r--package/aufs2-util/src/plink.c356
-rw-r--r--package/aufs2-util/src/proc_mnt.c85
-rw-r--r--package/aufs2-util/src/rdu.c749
-rwxr-xr-xpackage/aufs2-util/src/umount.aufs31
19 files changed, 4805 insertions, 0 deletions
diff --git a/package/aufs2-util/src/COPYING b/package/aufs2-util/src/COPYING
new file mode 100644
index 000000000..f90922eea
--- /dev/null
+++ b/package/aufs2-util/src/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/package/aufs2-util/src/Makefile b/package/aufs2-util/src/Makefile
new file mode 100644
index 000000000..c7aacfc14
--- /dev/null
+++ b/package/aufs2-util/src/Makefile
@@ -0,0 +1,103 @@
+
+# Copyright (C) 2005-2009 Junjiro Okajima
+#
+# This program, aufs is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ifndef KDIR
+KDIR = /lib/modules/$(shell uname -r)/build
+endif
+
+CFLAGS += -I${KDIR}/include
+CFLAGS += -O -Wall
+
+Cmd = umount.aufs auchk aubrsync
+Man = aufs.5
+Etc = etc_default_aufs
+Bin = auplink mount.aufs #auctl
+BinObj = $(addsuffix .o, ${Bin})
+LibSo = libau.so
+LibSoObj = rdu.o
+LibSoHdr = compat.h
+LibUtil = libautil.a
+LibUtilObj = proc_mnt.o br.o plink.o mtab.o
+LibUtilHdr = au_util.h
+
+all: ${Man} ${Bin} ${Etc} #${LibSo}
+
+${Bin}: LDFLAGS += -static -s
+${Bin}: LDLIBS = -L. -lautil
+${BinObj}: %.o: %.c ${LibUtilHdr} ${LibUtil}
+
+${LibUtilObj}: %.o: %.c ${LibUtilHdr}
+${LibUtil}: ${LibUtil}(${LibUtilObj})
+
+${LibSoObj}: CFLAGS += -fPIC
+${LibSoObj}: %.o: %.c ${LibSolHdr}
+
+# in order to reuse the default rule
+Dummy = $(basename $(word 1,${LibSoObj}))
+${Dummy}: LDFLAGS += --shared
+${Dummy}: LDLIBS += -ldl -lpthread
+${Dummy}: ${LibSoObj}
+${LibSo}: ${Dummy}
+ ln -f $< $@
+
+etc_default_aufs: c2sh aufs.shlib
+ ${RM} $@
+ echo '# aufs variables for shell scripts' > $@
+ ./c2sh >> $@
+ echo >> $@
+ sed -e '0,/^$$/d' aufs.shlib >> $@
+
+aufs.5: aufs.in.5 c2tmac
+ ${RM} $@
+ ./c2tmac > $@
+ awk '{ \
+ gsub(/\140[^\047]*\047/, "\\[oq]&\\[cq]"); \
+ gsub(/\\\[oq\]\140/, "\\[oq]"); \
+ gsub(/\047\\\[cq\]/, "\\[cq]"); \
+ gsub(/\047/, "\\[aq]"); \
+ print; \
+ }' aufs.in.5 >> $@
+ chmod a-w $@
+
+.INTERMEDIATE: c2sh c2tmac
+
+install_sbin: File = mount.aufs umount.aufs auplink
+install_sbin: Tgt = ${DESTDIR}/sbin
+install_ubin: File = auchk aubrsync #auctl
+install_ubin: Tgt = ${DESTDIR}/usr/bin
+install_man: File = aufs.5
+install_man: Tgt = ${DESTDIR}/usr/share/man/man5
+install_ulib: Opt = -s
+install_ulib: File = ${LibSo}
+install_ulib: Tgt = ${DESTDIR}/ulib
+install_sbin install_ubin install_man install_ulib: ${File}
+ install -d ${Tgt}
+ install -m 755 -o root -g root -p ${Opt} ${File} ${Tgt}
+install_etc: File = etc_default_aufs
+install_etc: Tgt = ${DESTDIR}/etc/default/aufs
+install_etc: ${File}
+ install -d $(dir ${Tgt})
+ install -m 644 -o root -g root -p -T ${File} ${Tgt}
+
+# do not inlcude install_ulib here
+install: install_man install_sbin install_ubin install_etc
+
+clean:
+ ${RM} ${Man} ${Bin} ${Etc} ${LibUtil} ${LibSo} *~
+ ${RM} ${BinObj} ${LibUtilObj} ${LibSoObj} ${Dummy}
+
+-include priv.mk
diff --git a/package/aufs2-util/src/README b/package/aufs2-util/src/README
new file mode 100644
index 000000000..1e1f45422
--- /dev/null
+++ b/package/aufs2-util/src/README
@@ -0,0 +1,46 @@
+
+Utilities for aufs2
+http://aufs.sf.net
+J. R. Okajima
+
+These utilities are always necessary for aufs2.
+If you forget to install them, your aufs may not work correctly.
+And these are not for aufs1 essentially, except aubrsync. See below in
+detail.
+
+Makefile in this tree has some customizable make-variables.
+- KDIR
+ specify your kernel source path if necessary
+- DESTDIR
+ specify your install path if necessary.
+ some commands have to be installed under /sbin.
+
+o /sbin/mount.aufs, /sbin/umount.aufs
+ Helpers for util-linux-ng package. You should NOT invoke them
+ manually. Just install them by "make install".
+
+o /sbin/auplink
+ Handles aufs pseudo-link at remount/unmount time. You can invoke it
+ manually at anytime.
+
+o /usr/bin/auchk
+ Similar to generic fsck. Checks whether a branch is healthy or not
+ from aufs's point of view.
+
+o /usr/bin/aubrsync
+ Move files from the upper writable branch to the lower branch.
+ If you use this script with aufs1, then you need to install aufs.shlib
+ to /usr/lib/aufs.shlib. Currently only the 20080211 version is tested
+ for aufs1.
+ The development of this script is sponcered by ASUSTek Computer Inc.
+ (http://www.asus.com/).
+ Kindly they agreed that I keep my aufs work as free software as it has
+ been.
+
+o /etc/default/aufs
+ A library for shell scripts.
+
+
+# Local variables: ;
+# mode: text;
+# End: ;
diff --git a/package/aufs2-util/src/au_util.h b/package/aufs2-util/src/au_util.h
new file mode 100644
index 000000000..21b965510
--- /dev/null
+++ b/package/aufs2-util/src/au_util.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2005-2009 Junjiro Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __AUFS_UTIL_H__
+#define __AUFS_UTIL_H__
+
+#include <errno.h>
+#include <error.h>
+
+/*
+ * error_at_line() is decleared with (__printf__, 5, 6) attribute,
+ * and our compiler produces a warning unless args is not given.
+ * __VA_ARGS__ does not help the attribute.
+ */
+#define AuFin(fmt, args...) \
+ error_at_line(errno, errno, __FILE__, __LINE__, fmt, ##args)
+
+#ifdef DEBUG
+#define MTab "/tmp/mtab"
+#else
+#define MTab "/etc/mtab"
+#endif
+
+/* proc_mounts.c */
+struct mntent;
+int au_proc_getmntent(char *mntpnt, struct mntent *rent);
+
+/* br.c */
+int au_br(char ***br, int *nbr, struct mntent *ent);
+
+/* plink.c */
+enum {
+ AuPlink_FLUSH,
+ AuPlink_CPUP,
+ AuPlink_LIST
+};
+int au_plink(char cwd[], int cmd, int begin_maint, int end_maint);
+void au_plink_maint(char *path);
+
+/* mtab.c */
+void au_print_ent(struct mntent *ent);
+int au_update_mtab(char *mntpnt, int do_remount, int do_verbose);
+
+#define _Dpri(fmt, ...) printf("%s:%d:" fmt, \
+ __func__, __LINE__, ##__VA_ARGS__)
+#ifdef DEBUG
+#define Dpri(fmt, ...) _Dpri(fmt, ##__VA_ARGS__)
+#else
+#define Dpri(fmt, ...) do { } while(0)
+#endif
+
+#endif /* __AUFS_UTIL_H__ */
diff --git a/package/aufs2-util/src/aubrsync b/package/aufs2-util/src/aubrsync
new file mode 100755
index 000000000..54adac9cb
--- /dev/null
+++ b/package/aufs2-util/src/aubrsync
@@ -0,0 +1,304 @@
+#!/bin/sh
+
+# Copyright (C) 2005-2009 Junjiro Okajima
+#
+# This program, aufs is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+#
+# The development of this script is sponcered by ASUSTek Computer Inc.
+# Kindly they agreed that I keep my aufs work as free software as it has
+# been.
+#
+
+set -eu
+#set -x
+
+me=$(basename $0)
+EEcho() # str
+{
+ echo ${me}: $@ 1>&2
+}
+
+f=/sbin/mount.aufs
+test ! -x $f && EEcho $f is not installed && exit 1
+
+# special handling for backward compatibility.
+#
+# aufs in the donated eeepc is aufs1 20080211 without CONFIG_AUFS_COMPAT.
+# /etc/default/aufs was introduced in aufs1 20080922.
+# shwh/noshwh was introduced in aufs1 20080310 with CONFIG_AUFS_SHWH.
+# noshwh became always available regardless CONFIG_AUFS_SHWH in aufs1 20081117.
+
+noshwh=1
+AUFS_VERSION=20080211
+f=/etc/default/aufs
+if [ -s $f ]
+then
+ . $f
+else
+ echo ${me}: warning, broken $f, assuming aufs is $AUFS_VERSION
+ f=/usr/lib/aufs.shlib
+ test ! -s $f && EEcho $f is not installed && exit 1
+ . $f
+
+ case $AUFS_VERSION in
+ 200*) # aufs1
+ test $AUFS_VERSION -lt 20081117 && noshwh=0
+ ;;
+ esac
+ AUFS_SUPER_MAGIC=1635083891
+ AUFS_SUPER_MAGIC_HEX=0x61756673
+ AUFS_WH_PFX=.wh.
+ AUFS_WH_PFX2=.wh..wh.
+ AUFS_WH_DIROPQ=.wh..wh..opq
+fi
+
+########################################
+
+_Rsync="rsync --exclude=lost+found"
+Rsync="$_Rsync -aHSx --devices --specials --delete-before"
+Copy="$Rsync"
+Move="$Copy"
+RsyncWh="$_Rsync -ptgoHx"
+
+FindForRm() # rw
+{
+ echo "find \"$1\" -xdev -depth \(
+ \( ! -type d
+ \( -name $AUFS_WH_DIROPQ
+ -o ! -name ${AUFS_WH_PFX2}\* \) \)
+ -o \( -type d
+ ! -name ${AUFS_WH_PFX2}\*
+ ! -wholename \"$1\"
+ ! -wholename \"$1/lost+found\" \)
+ \) -print0"
+}
+
+MoveWh() # rw ro+wh
+{
+ cd "$1"
+ find . -xdev -name ${AUFS_WH_PFX}\* ! -name ${AUFS_WH_PFX2}\* \
+ -printf '%P\n' |
+ while read wh
+ do
+ f=$(echo "$wh" | sed -e '
+ s/^'${AUFS_WH_PFX}'//
+ t
+ s:/'${AUFS_WH_PFX}':/:
+ ')
+ test -e "$dst/$f" || echo "$wh"
+ done |
+ # -v
+ $RsyncWh --files-from=- ./ "$2"
+ cd "$OLDPWD"
+}
+
+copy()
+{
+ $Copy $@ "$mntpnt"/ "$dst"
+}
+
+_move()
+{
+ set +x
+ test $hinotify -ne 1 && echo ${me}: warning, -i is not specified
+ src_is_nfs=0
+ test $(stat -f -c %T "$src") = nfs && src_is_nfs=1
+ set $quiet
+
+ $Move $@ &&
+ eval $(FindForRm "$src") |
+ {
+ if [ $src_is_nfs -eq 1 ]
+ then
+ mount -o remount "$mntpnt"
+ mount -o remount "$src"
+ fi
+ xargs -r0 rm -fr #-v
+ }
+}
+
+move()
+{
+ _move $@ "$mntpnt"/ "$dst"
+}
+
+move_with_wh()
+{
+ {
+ set +x
+ MoveWh "$src" "$dst"
+ set $quiet
+ } &&
+ move --exclude=${AUFS_WH_PFX}\*
+}
+
+# backward compatibility
+move_w()
+{
+ move_with_wh $@
+}
+
+Usage()
+{
+ t=$(FindForRm src_branch | sed -e '
+ s/"//g
+ $b
+ s/$/ \\/')
+
+ cat <<- EOF
+ $me Options move | move_with_wh | copy \\
+ mntpnt src_branch dst_branch [ options for rsync ]
+
+ generic form:
+ $me [ -w | --wh ] [ -i | --inotify ] Options \\
+ mntpnt cmd [ parameters for cmd ]
+
+ Options:
+ [ -n | --dry_run ]
+ [ -q | --quiet ]
+
+ The dst_branch must be mounted as writable.
+ During the operation, the mntpnt is set readonly.
+ If you are opening a file for writing on the writable branch,
+ you need to close the file before invoking this script.
+ The -w or --wh option requires CONFIG_AUFS_SHWH enabled.
+ The -i or --inotify option requires CONFIG_AUFS_HINOTIFY enabled.
+
+ 'copy' is a shortcut for
+ $me mntpnt \\
+ $Copy mntpnt/ dst_branch
+ 'move' is a shortcut for
+ $me mntpnt \\
+ "$Move \\
+ mntpnt/ dst_branch && \\
+ $t |\\
+ xargs -r0 rm -fr"
+ Note: in most cases, you will need '-i' option, and
+ find(1) is invoked by $me only when rsync(1)
+ succeded.
+ 'move_with_wh' is a simple variation of 'move' which moves
+ whiteouts separately before the actual 'move'.
+
+ If you execute this script under linux-2.6.24 or earlier, the
+ kernel may produce a harmless warning "inotify.c:NNN
+ set_dentry_child_flags()". The message was already removed in
+ linux-2.6.25.
+
+ examples:
+ - Copy and reflect all the modification (modifed files, newly
+ created and removed ones) in the upper branch to the lower
+ branch. This operation is for aufs which has only 2 branches,
+ and mainly for a system shutdown script.
+ All files on the upper branch remain.
+
+ $ sudo $me copy /your/aufs /your/upper_branch /your/lower_branch
+
+ - Like above (2 branches), move and reflect all modifications
+ from upper to lower. Almost all files on the upper branch will
+ be removed. You can still use this aufs after the
+ operation. But the inode number may be changed. If your
+ application which depends upon the inode number was running at
+ that time, it may not work correctly.
+
+ $ sudo $me move /your/aufs /your/upper_branch /your/lower_branch
+ EOF
+
+# - Like above (2 branches), generate a new middle layer like a
+# snapshot including whiteouts and make the upper_branch almost
+# empty, but untouch the lower_branch.
+#
+# $ img=/hda1/a.ext2
+# $ dd if=/dev/zero of=\$img bs=4k count=1k
+# $ mkfs -t ext2 -F \$img
+# $ sudo mount -o rw,loop \$img /your/new_branch
+# $ sudo mount -o remount,ins:1:/your/new_branch=ro+wh /your/aufs
+# $ sudo $me _move /your/aufs /your/upper_branch /your/lower_branch \\
+# "--remove-source-files \\
+# --exclude=$AUFS_WH_BASE \\
+# --exclude=$AUFS_WH_PLINKDIR \\
+# --exclude=$AUFS_WH_TMPDIR \\
+# /your/upper_branch/ /your/new_branch; \\
+# mount -o remount,ro /your/new_branch"
+# EOF
+}
+
+########################################
+
+wh=0
+hinotify=0
+quiet=-x
+dry_run=
+cmd=
+cmd_opts=
+for i
+do
+ case $i in
+ -w|--wh) wh=1;;
+ -i|--inotify) hinotify=1;;
+ -n|--dry_run) dry_run=echo;;
+ -q|--quiet) quiet=+x;;
+ -h|--help) Usage; exit 0;;
+ --) shift; break;;
+ *) break;;
+ esac
+ shift
+done
+
+test $# -lt 2 && Usage 1>&2 && exit 1
+case "$1" in
+_move|move|copy|move_w|move_with_wh)
+ test $# -lt 4 && Usage 1>&2 && exit 1
+ cmd=$1
+ SetDir mntpnt "$2"
+ SetDir src "$3"
+ SetDir dst "$4"
+ shift 4
+ wh=0
+ ;;
+*)
+ SetDir mntpnt "$1"
+ cmd="$2"
+ shift 2
+ ;;
+esac
+cmd_opts="$@"
+
+case $(stat -f -c %T "$mntpnt") in
+aufs|UNKNOWN*${AUFS_SUPER_MAGIC_HEX}*) ;;
+*)
+ EEcho "$mntpnt" is not aufs
+ exit 1
+ ;;
+esac
+
+cur_opts=$(MntOpts "$mntpnt")
+test ! "$cur_opts" &&
+EEcho bad /proc/mounts or "$mntpnt" is not mounted &&
+exit 1
+cur_opts="udba=reval,noshwh,$cur_opts"
+test $noshwh -eq 0 && cur_opts=$(echo $cur_opts | sed -e 's/,noshwh//')
+
+# force flushing the pusedo-links
+tmp_opts="remount,ro,udba=reval,noshwh"
+test $noshwh -eq 0 && tmp_opts=$(echo $tmp_opts | sed -e 's/,noshwh//')
+test $wh -eq 1 && tmp_opts="$tmp_opts,shwh"
+test $hinotify -eq 1 && tmp_opts="$tmp_opts,udba=inotify"
+
+# here we go
+trap "$dry_run mount -o remount,$cur_opts \"$mntpnt\"" EXIT
+set $quiet
+$dry_run mount -o $tmp_opts "$mntpnt"
+eval "$dry_run $cmd $cmd_opts"
diff --git a/package/aufs2-util/src/auchk b/package/aufs2-util/src/auchk
new file mode 100755
index 000000000..26a3d8027
--- /dev/null
+++ b/package/aufs2-util/src/auchk
@@ -0,0 +1,130 @@
+#!/bin/sh -
+
+# Copyright (C) 2005-2009 Junjiro Okajima
+#
+# This program, aufs is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+set -eu
+#set -x
+
+EEcho() # str
+{
+ echo $0: $@ 1>&2
+}
+
+f=/etc/default/aufs
+. $f
+
+Usage()
+{
+ echo $0 writable_branch '[...]'
+}
+
+Pass() # title
+{
+ pass=$(($pass + 1))
+ EEcho \[Pass $pass\] $@
+}
+
+Remove() # file
+{
+ if [ -d "$1" ]
+ then
+ rm -ir "$1" || :
+ else
+ rm -v "$1" || :
+ fi
+}
+
+for i
+do
+ EEcho Checking "$i" for aufs
+
+ cd "$i"
+ case $(stat -f -c %T .) in
+ aufs|UNKNOWN*${AUFS_SUPER_MAGIC_HEX}*)
+ EEcho $i must not be aufs
+ cd $OLDPWD
+ continue
+ ;;
+ esac
+
+ ########################################
+ pass=0
+ Pass Illegal whiteout
+ find . -name '.wh.*' ! -name '.wh..wh.*' -printf '%h\0%f\0' |
+ xargs -r0n2 |
+ while read dir wh
+ do
+ #echo \""$dir"\" \""$wh"\"
+ base=$(echo "$wh" | cut -c5-)
+ test ! -e "$dir/$base" && continue
+
+ ls -ld "$dir/$wh" "$dir/$base"
+ read -p 'Which to remove [whiteout/real/skip]? ' ans \
+ < /dev/tty > /dev/tty 2>&1
+ case "$ans" in
+ [wW]*) Remove "$dir/$wh" || :;;
+ [rR]*) Remove "$dir/$base" || :;;
+ *) echo skipped;;
+ esac
+ done
+
+ ########################################
+ Pass Remained pseudo-links
+ did=0
+ for plink in ${AUFS_WH_PLINKDIR}/*
+ do
+ test ! -e "$plink" && break
+ if [ -d "$plink" ]
+ then
+ EEcho illegal "$plink"
+ continue
+ fi
+
+ did=1
+ #ls -l "$plink" || :
+ find . -inum $(basename "$plink" | cut -f2 -d .) -ls || :
+ done
+ if [ $did -ne 0 ]
+ then
+ cat <<- EOF
+ They will be maintained at remount or umount time,
+ if you installed aufs helper scripts (See README
+ in detail).
+ If "$i" is not a writeble branch of CURRENTLY mounted
+ aufs, you need to maintain them by yourself.
+ EOF
+ fi
+
+ ########################################
+ Pass Remained temp files
+ for tmp in ${AUFS_WH_TMPDIR}/*
+ do
+ test ! -e "$tmp" && break
+ if [ -d "$tmp" ]
+ then
+ EEcho illegal "$tmp"
+ continue
+ fi
+
+ ls -l "$tmp" || :
+ rm -i "$tmp" || :
+ done
+
+ # nothing to do for xinodir
+
+ cd $OLDPWD
+done
diff --git a/package/aufs2-util/src/aufs.in.5 b/package/aufs2-util/src/aufs.in.5
new file mode 100644
index 000000000..0cbb14487
--- /dev/null
+++ b/package/aufs2-util/src/aufs.in.5
@@ -0,0 +1,1684 @@
+.\".so aufs.tmac
+.
+.eo
+.de TQ
+.br
+.ns
+.TP \$1
+..
+.de Bu
+.IP \(bu 4
+..
+.ec
+.\" end of macro definitions
+.
+.\" ----------------------------------------------------------------------
+.TH aufs 5 \*[AUFS_VERSION] Linux "Linux Aufs User's Manual"
+.SH NAME
+aufs \- advanced multi layered unification filesystem. version \*[AUFS_VERSION]
+
+.\" ----------------------------------------------------------------------
+.SH DESCRIPTION
+Aufs is a stackable unification filesystem such as Unionfs, which unifies
+several directories and provides a merged single directory.
+In the early days, aufs was entirely re-designed and re-implemented
+Unionfs Version 1.x series. After
+many original ideas, approaches and improvements, it
+becomes totally different from Unionfs while keeping the basic features.
+See Unionfs Version 1.x series for the basic features.
+Recently, Unionfs Version 2.x series begin taking some of same
+approaches to aufs's.
+
+.\" ----------------------------------------------------------------------
+.SH MOUNT OPTIONS
+At mount-time, the order of interpreting options is,
+.RS
+.Bu
+simple flags, except xino/noxino and udba=inotify
+.Bu
+branches
+.Bu
+xino/noxino
+.Bu
+udba=inotify
+.RE
+
+At remount-time,
+the options are interpreted in the given order,
+e.g. left to right.
+.RS
+.Bu
+create or remove
+whiteout-base(\*[AUFS_WH_BASE]) and
+whplink-dir(\*[AUFS_WH_PLINKDIR]) if necessary
+.RE
+.
+.TP
+.B br:BRANCH[:BRANCH ...] (dirs=BRANCH[:BRANCH ...])
+Adds new branches.
+(cf. Branch Syntax).
+
+Aufs rejects the branch which is an ancestor or a descendant of another
+branch. It is called overlapped. When the branch is loopback-mounted
+directory, aufs also checks the source fs-image file of loopback
+device. If the source file is a descendant of another branch, it will
+be rejected too.
+
+After mounting aufs or adding a branch, if you move a branch under
+another branch and make it descendant of another branch, aufs will not
+work correctly.
+.
+.TP
+.B [ add | ins ]:index:BRANCH
+Adds a new branch.
+The index begins with 0.
+Aufs creates
+whiteout-base(\*[AUFS_WH_BASE]) and
+whplink-dir(\*[AUFS_WH_PLINKDIR]) if necessary.
+
+If there is the same named file on the lower branch (larger index),
+aufs will hide the lower file.
+You can only see the highest file.
+You will be confused if the added branch has whiteouts (including
+diropq), they may or may not hide the lower entries.
+.\" It is recommended to make sure that the added branch has no whiteout.
+
+Even if a process have once mapped a file by mmap(2) with MAP_SHARED
+and the same named file exists on the lower branch,
+the process still refers the file on the lower(hidden)
+branch after adding the branch.
+If you want to update the contents of a process address space after
+adding, you need to restart your process or open/mmap the file again.
+.\" Usually, such files are executables or shared libraries.
+(cf. Branch Syntax).
+.
+.TP
+.B del:dir
+Removes a branch.
+Aufs does not remove
+whiteout-base(\*[AUFS_WH_BASE]) and
+whplink-dir(\*[AUFS_WH_PLINKDIR]) automatically.
+For example, when you add a RO branch which was unified as RW, you
+will see whiteout-base or whplink-dir on the added RO branch.
+
+If a process is referencing the file/directory on the deleting branch
+(by open, mmap, current working directory, etc.), aufs will return an
+error EBUSY.
+.
+.TP
+.B mod:BRANCH
+Modifies the permission flags of the branch.
+Aufs creates or removes
+whiteout-base(\*[AUFS_WH_BASE]) and/or
+whplink-dir(\*[AUFS_WH_PLINKDIR]) if necessary.
+
+If the branch permission is been changing `rw' to `ro', and a process
+is mapping a file by mmap(2)
+.\" with MAP_SHARED
+on the branch, the process may or may not
+be able to modify its mapped memory region after modifying branch
+permission flags.
+Additioanlly when you enable CONFIG_IMA (in linux-2.6.30 and later), IMA
+may produce some wrong messages. But this is equivalent when the
+filesystem is changed `ro' in emergency.
+(cf. Branch Syntax).
+.
+.TP
+.B append:BRANCH
+equivalent to `add:(last index + 1):BRANCH'.
+(cf. Branch Syntax).
+.
+.TP
+.B prepend:BRANCH
+equivalent to `add:0:BRANCH.'
+(cf. Branch Syntax).
+.
+.TP
+.B xino=filename
+Use external inode number bitmap and translation table.
+When CONFIG_AUFS_EXPORT is enabled, external inode generation table too.
+It is set to
+<FirstWritableBranch>/\*[AUFS_XINO_FNAME] by default, or
+\*[AUFS_XINO_DEFPATH].
+Comma character in filename is not allowed.
+
+The files are created per an aufs and per a branch filesystem, and
+unlinked. So you
+cannot find this file, but it exists and is read/written frequently by
+aufs.
+(cf. External Inode Number Bitmap, Translation Table and Generation Table).
+
+If you enable CONFIG_SYSFS, the path of xino files are not shown in
+/proc/mounts (and /etc/mtab), instead it is shown in
+<sysfs>/fs/aufs/si_<id>/xi_path.
+Otherwise, it is shown in /proc/mounts unless it is not the default
+path.
+.
+.TP
+.B noxino
+Stop using external inode number bitmap and translation table.
+
+If you use this option,
+Some applications will not work correctly.
+.\" And pseudo link feature will not work after the inode cache is
+.\" shrunk.
+(cf. External Inode Number Bitmap, Translation Table and Generation Table).
+.
+.TP
+.B trunc_xib
+Truncate the external inode number bitmap file. The truncation is done
+automatically when you delete a branch unless you do not specify
+`notrunc_xib' option.
+(cf. External Inode Number Bitmap, Translation Table and Generation Table).
+.
+.TP
+.B notrunc_xib
+Stop truncating the external inode number bitmap file when you delete
+a branch.
+(cf. External Inode Number Bitmap, Translation Table and Generation Table).
+.
+.TP
+.B create_policy | create=CREATE_POLICY
+.TQ
+.B copyup_policy | copyup | cpup=COPYUP_POLICY
+Policies to select one among multiple writable branches. The default
+values are `create=tdp' and `cpup=tdp'.
+link(2) and rename(2) systemcalls have an exception. In aufs, they
+try keeping their operations in the branch where the source exists.
+(cf. Policies to Select One among Multiple Writable Branches).
+.
+.TP
+.B verbose | v
+Print some information.
+Currently, it is only busy file (or inode) at deleting a branch.
+.
+.TP
+.B noverbose | quiet | q | silent
+Disable `verbose' option.
+This is default value.
+.
+.TP
+.B sum
+df(1)/statfs(2) returns the total number of blocks and inodes of
+all branches.
+Note that there are cases that systemcalls may return ENOSPC, even if
+df(1)/statfs(2) shows that aufs has some free space/inode.
+.
+.TP
+.B nosum
+Disable `sum' option.
+This is default value.
+.
+.TP
+.B dirwh=N
+Watermark to remove a dir actually at rmdir(2) and rename(2).
+
+If the target dir which is being removed or renamed (destination dir)
+has a huge number of whiteouts, i.e. the dir is empty logically but
+physically, the cost to remove/rename the single
+dir may be very high.
+It is
+required to unlink all of whiteouts internally before issuing
+rmdir/rename to the branch.
+To reduce the cost of single systemcall,
+aufs renames the target dir to a whiteout-ed temporary name and
+invokes a pre-created
+kernel thread to remove whiteout-ed children and the target dir.
+The rmdir/rename systemcall returns just after kicking the thread.
+
+When the number of whiteout-ed children is less than the value of
+dirwh, aufs remove them in a single systemcall instead of passing
+another thread.
+This value is ignored when the branch is NFS.
+The default value is \*[AUFS_DIRWH_DEF].
+.\" .
+.\" .TP
+.\" .B rdcache=N
+.
+.TP
+.B rdblk=N
+Specifies a size of internal VDIR block which is allocated at a time in
+byte.
+The VDIR block will be allocated several times when necessary. If your
+directory has millions of files, you may want to expand this size.
+The default value is defined as \*[AUFS_RDBLK_DEF].
+The size has to be lager than NAME_MAX (usually 255) and kmalloc\-able
+(the maximum limit depends on your system. at least 128KB is available
+for every system).
+Whenever you can reset the value to default by specifying rdblk=def.
+(cf. Virtual or Vertical Directory Block).
+.
+.TP
+.B rdhash=N
+Specifies a size of internal VDIR hash table which is used to compare
+the file names under the same named directory on multiple branches.
+The VDIR hash table will be allocated in readdir(3)/getdents(2),
+rmdir(2) and rename(2) for the existing target directory. If your
+directory has millions of files, you may want to expand this size.
+The default value is defined as \*[AUFS_RDHASH_DEF].
+The size has to be lager than zero, and it will be multiplied by 4 or 8
+(for 32\-bit and 64\-bit respectively, currently). The result must be
+kmalloc\-able
+(the maximum limit depends on your system. at least 128KB is available
+for every system).
+Whenever you can reset the value to default by specifying rdhash=def.
+(cf. Virtual or Vertical Directory Block).
+.
+.TP
+.B plink
+.TQ
+.B noplink
+Specifies to use `pseudo link' feature or not.
+The default is `plink' which means use this feature.
+(cf. Pseudo Link)
+.
+.TP
+.B clean_plink
+Removes all pseudo-links in memory.
+In order to make pseudo-link permanent, use
+`auplink' utility just before one of these operations,
+unmounting aufs,
+using `ro' or `noplink' mount option,
+deleting a branch from aufs,
+adding a branch into aufs,
+or changing your writable branch as readonly.
+If you installed both of /sbin/mount.aufs and /sbin/umount.aufs, and your
+mount(8) and umount(8) support them,
+`auplink' utility will be executed automatically and flush pseudo-links.
+(cf. Pseudo Link)
+.
+.TP
+.B udba=none | reval | inotify
+Specifies the level of UDBA (User's Direct Branch Access) test.
+(cf. User's Direct Branch Access and Inotify Limitation).
+.
+.TP
+.B diropq=whiteouted | w | always | a
+Specifies whether mkdir(2) and rename(2) dir case make the created directory
+`opaque' or not.
+In other words, to create `\*[AUFS_WH_DIROPQ]' under the created or renamed
+directory, or not to create.
+When you specify diropq=w or diropq=whiteouted, aufs will not create
+it if the
+directory was not whiteouted or opaqued. If the directory was whiteouted
+or opaqued, the created or renamed directory will be opaque.
+When you specify diropq=a or diropq==always, aufs will always create
+it regardless
+the directory was whiteouted/opaqued or not.
+The default value is diropq=w, it means not to create when it is unnecessary.
+If you define CONFIG_AUFS_COMPAT at aufs compiling time, the default will be
+diropq=a.
+You need to consider this option if you are planning to add a branch later
+since `diropq' affects the same named directory on the added branch.
+.
+.TP
+.B warn_perm
+.TQ
+.B nowarn_perm
+Adding a branch, aufs will issue a warning about uid/gid/permission of
+the adding branch directory,
+when they differ from the existing branch's. This difference may or
+may not impose a security risk.
+If you are sure that there is no problem and want to stop the warning,
+use `nowarn_perm' option.
+The default is `warn_perm' (cf. DIAGNOSTICS).
+.
+.TP
+.B shwh
+.TQ
+.B noshwh
+By default (noshwh), aufs doesn't show the whiteouts and
+they just hide the same named entries in the lower branches. The
+whiteout itself also never be appeared.
+If you enable CONFIG_AUFS_SHWH and specify `shwh' option, aufs
+will show you the name of whiteouts
+with keeping its feature to hide the lowers.
+Honestly speaking, I am rather confused with this `visible whiteouts.'
+But a user who originally requested this feature wrote a nice how-to
+document about this feature. See Tips file in the aufs CVS tree.
+
+.\" ----------------------------------------------------------------------
+.SH Module Parameters
+.TP
+.B nwkq=N
+The number of kernel thread named \*[AUFS_WKQ_NAME].
+
+Those threads stay in the system while the aufs module is loaded,
+and handle the special I/O requests from aufs.
+The default value is \*[AUFS_NWKQ_DEF].
+
+The special I/O requests from aufs include a part of copy-up, lookup,
+directory handling, pseudo-link, xino file operations and the
+delegated access to branches.
+For example, Unix filesystems allow you to rmdir(2) which has no write
+permission bit, if its parent directory has write permission bit. In aufs, the
+removing directory may or may not have whiteout or `dir opaque' mark as its
+child. And aufs needs to unlink(2) them before rmdir(2).
+Therefore aufs delegates the actual unlink(2) and rmdir(2) to another kernel
+thread which has been created already and has a superuser privilege.
+
+If you enable CONFIG_SYSFS, you can check this value through
+<sysfs>/module/aufs/parameters/nwkq.
+
+.
+.TP
+.B brs=1 | 0
+Specifies to use the branch path data file under sysfs or not.
+
+If the number of your branches is large or their path is long
+and you meet the limitation of mount(8) ro /etc/mtab, you need to
+enable CONFIG_SYSFS and set aufs module parameter brs=1.
+
+When this parameter is set as 1, aufs does not show `br:' (or dirs=)
+mount option through /proc/mounts (and /etc/mtab). So you can
+keep yourself from the page limitation of
+mount(8) or /etc/mtab.
+Aufs shows branch paths through <sysfs>/fs/aufs/si_XXX/brNNN.
+Actually the file under sysfs has also a size limitation, but I don't
+think it is harmful.
+
+There is one more side effect in setting 1 to this parameter.
+If you rename your branch, the branch path written in /etc/mtab will be
+obsoleted and the future remount will meet some error due to the
+unmatched parameters (Remember that mount(8) may take the options from
+/etc/mtab and pass them to the systemcall).
+If you set 1, /etc/mtab will not hold the branch path and you will not
+meet such trouble. On the other hand, the entries for the
+branch path under sysfs are generated dynamically. So it must not be obsoleted.
+But I don't think users want to rename branches so often.
+
+If CONFIG_SYSFS is disable, this parameter is always set to 0.
+.
+.TP
+.B sysrq=key
+Specifies MagicSysRq key for debugging aufs.
+You need to enable both of CONFIG_MAGIC_SYSRQ and CONFIG_AUFS_DEBUG.
+Currently this is for developers only.
+The default is `a'.
+.
+.TP
+.B debug= 0 | 1
+Specifies disable(0) or enable(1) debug print in aufs.
+This parameter can be changed dynamically.
+You need to enable CONFIG_AUFS_DEBUG.
+Currently this is for developers only.
+The default is `0' (disable).
+
+.\" ----------------------------------------------------------------------
+.SH Entries under Sysfs and Debugfs
+See linux/Documentation/ABI/*/{sys,debug}fs-aufs.
+
+.\" ----------------------------------------------------------------------
+.SH Branch Syntax
+.TP
+.B dir_path[ =permission [ + attribute ] ]
+.TQ
+.B permission := rw | ro | rr
+.TQ
+.B attribute := wh | nolwh
+dir_path is a directory path.
+The keyword after `dir_path=' is a
+permission flags for that branch.
+Comma, colon and the permission flags string (including `=')in the path
+are not allowed.
+
+Any filesystem can be a branch, But some are not accepted such like
+sysfs, procfs and unionfs.
+If you specify such filesystems as an aufs branch, aufs will return an error
+saying it is unsupported.
+
+Cramfs in linux stable release has strange inodes and it makes aufs
+confused. For example,
+.nf
+$ mkdir -p w/d1 w/d2
+$ > w/z1
+$ > w/z2
+$ mkcramfs w cramfs
+$ sudo mount -t cramfs -o ro,loop cramfs /mnt
+$ find /mnt -ls
+ 76 1 drwxr-xr-x 1 jro 232 64 Jan 1 1970 /mnt
+ 1 1 drwxr-xr-x 1 jro 232 0 Jan 1 1970 /mnt/d1
+ 1 1 drwxr-xr-x 1 jro 232 0 Jan 1 1970 /mnt/d2
+ 1 1 -rw-r--r-- 1 jro 232 0 Jan 1 1970 /mnt/z1
+ 1 1 -rw-r--r-- 1 jro 232 0 Jan 1 1970 /mnt/z2
+.fi
+
+All these two directories and two files have the same inode with one
+as their link count. Aufs cannot handle such inode correctly.
+Currently, aufs involves a tiny workaround for such inodes. But some
+applications may not work correctly since aufs inode number for such
+inode will change silently.
+If you do not have any empty files, empty directories or special files,
+inodes on cramfs will be all fine.
+
+A branch should not be shared as the writable branch between multiple
+aufs. A readonly branch can be shared.
+
+The maximum number of branches is configurable at compile time (127 by
+default).
+
+When an unknown permission or attribute is given, aufs sets ro to that
+branch silently.
+
+.SS Permission
+.
+.TP
+.B rw
+Readable and writable branch. Set as default for the first branch.
+If the branch filesystem is mounted as readonly, you cannot set it `rw.'
+.\" A filesystem which does not support link(2) and i_op\->setattr(), for
+.\" example FAT, will not be used as the writable branch.
+.
+.TP
+.B ro
+Readonly branch and it has no whiteouts on it.
+Set as default for all branches except the first one. Aufs never issue
+both of write operation and lookup operation for whiteout to this branch.
+.
+.TP
+.B rr
+Real readonly branch, special case of `ro', for natively readonly
+branch. Assuming the branch is natively readonly, aufs can optimize
+some internal operation. For example, if you specify `udba=inotify'
+option, aufs does not set inotify for the things on rr branch.
+Set by default for a branch whose fs-type is either `iso9660',
+`cramfs' or `romfs' (and `squashfs' for linux\-2.6.29 and later).
+
+When your branch exists on slower device and you have some
+capacity on your hdd, you may want to try ulobdev tool in ULOOP sample.
+It can cache the contents of the real devices on another faster device,
+so you will be able to get the better access performance.
+The ulobdev tool is for a generic block device, and the ulohttp is for a
+filesystem image on http server.
+If you want to spin down your hdd to save the
+battery life or something, then you may want to use ulobdev to save the
+access to the hdd, too.
+See $AufsCVS/sample/uloop in detail.
+
+.SS Attribute
+.
+.TP
+.B wh
+Readonly branch and it has/might have whiteouts on it.
+Aufs never issue write operation to this branch, but lookup for whiteout.
+Use this as `<branch_dir>=ro+wh'.
+.
+.TP
+.B nolwh
+Usually, aufs creates a whiteout as a hardlink on a writable
+branch. This attributes prohibits aufs to create the hardlinked
+whiteout, including the source file of all hardlinked whiteout
+(\*[AUFS_WH_BASE].)
+If you do not like a hardlink, or your writable branch does not support
+link(2), then use this attribute.
+But I am afraid a filesystem which does not support link(2) natively
+will fail in other place such as copy-up.
+Use this as `<branch_dir>=rw+nolwh'.
+Also you may want to try `noplink' mount option, while it is not recommended.
+
+.\" .SS FUSE as a branch
+.\" A FUSE branch needs special attention.
+.\" The struct fuse_operations has a statfs operation. It is OK, but the
+.\" parameter is struct statvfs* instead of struct statfs*. So almost
+.\" all user\-space implementation will call statvfs(3)/fstatvfs(3) instead of
+.\" statfs(2)/fstatfs(2).
+.\" In glibc, [f]statvfs(3) issues [f]statfs(2), open(2)/read(2) for
+.\" /proc/mounts,
+.\" and stat(2) for the mountpoint. With this situation, a FUSE branch will
+.\" cause a deadlock in creating something in aufs. Here is a sample
+.\" scenario,
+.\" .\" .RS
+.\" .\" .IN -10
+.\" .Bu
+.\" create/modify a file just under the aufs root dir.
+.\" .Bu
+.\" aufs acquires a write\-lock for the parent directory, ie. the root dir.
+.\" .Bu
+.\" A library function or fuse internal may call statfs for a fuse branch.
+.\" The create=mfs mode in aufs will surely call statfs for each writable
+.\" branches.
+.\" .Bu
+.\" FUSE in kernel\-space converts and redirects the statfs request to the
+.\" user\-space.
+.\" .Bu
+.\" the user\-space statfs handler will call [f]statvfs(3).
+.\" .Bu
+.\" the [f]statvfs(3) in glibc will access /proc/mounts and issue
+.\" stat(2) for the mountpoint. But those require a read\-lock for the aufs
+.\" root directory.
+.\" .Bu
+.\" Then a deadlock occurs.
+.\" .\" .RE 1
+.\" .\" .IN
+.\"
+.\" In order to avoid this deadlock, I would suggest not to call
+.\" [f]statvfs(3) from fuse. Here is a sample code to do this.
+.\" .nf
+.\" struct statvfs stvfs;
+.\"
+.\" main()
+.\" {
+.\" statvfs(..., &stvfs)
+.\" or
+.\" fstatvfs(..., &stvfs)
+.\" stvfs.f_fsid = 0
+.\" }
+.\"
+.\" statfs_handler(const char *path, struct statvfs *arg)
+.\" {
+.\" struct statfs stfs
+.\"
+.\" memcpy(arg, &stvfs, sizeof(stvfs))
+.\"
+.\" statfs(..., &stfs)
+.\" or
+.\" fstatfs(..., &stfs)
+.\"
+.\" arg->f_bfree = stfs.f_bfree
+.\" arg->f_bavail = stfs.f_bavail
+.\" arg->f_ffree = stfs.f_ffree
+.\" arg->f_favail = /* any value */
+.\" }
+.\" .fi
+
+.\" ----------------------------------------------------------------------
+.SH External Inode Number Bitmap, Translation Table and Generation Table (xino)
+Aufs uses one external bitmap file and one external inode number
+translation table files per an aufs and per a branch
+filesystem by default.
+Additionally when CONFIG_AUFS_EXPORT is enabled, one external inode
+generation table is added.
+The bitmap (and the generation table) is for recycling aufs inode number
+and the others
+are a table for converting an inode number on a branch to
+an aufs inode number. The default path
+is `first writable branch'/\*[AUFS_XINO_FNAME].
+If there is no writable branch, the
+default path
+will be \*[AUFS_XINO_DEFPATH].
+.\" A user who executes mount(8) needs the privilege to create xino
+.\" file.
+
+If you enable CONFIG_SYSFS, the path of xino files are not shown in
+/proc/mounts (and /etc/mtab), instead it is shown in
+<sysfs>/fs/aufs/si_<id>/xi_path.
+Otherwise, it is shown in /proc/mounts unless it is not the default
+path.
+
+Those files are always opened and read/write by aufs frequently.
+If your writable branch is on flash memory device, it is recommended
+to put xino files on other than flash memory by specifying `xino='
+mount option.
+
+The
+maximum file size of the bitmap is, basically, the amount of the
+number of all the files on all branches divided by 8 (the number of
+bits in a byte).
+For example, on a 4KB page size system, if you have 32,768 (or
+2,599,968) files in aufs world,
+then the maximum file size of the bitmap is 4KB (or 320KB).
+
+The
+maximum file size of the table will
+be `max inode number on the branch x size of an inode number'.
+For example in 32bit environment,
+
+.nf
+$ df -i /branch_fs
+/dev/hda14 2599968 203127 2396841 8% /branch_fs
+.fi
+
+and /branch_fs is an branch of the aufs. When the inode number is
+assigned contiguously (without `hole'), the maximum xino file size for
+/branch_fs will be 2,599,968 x 4 bytes = about 10 MB. But it might not be
+allocated all of disk blocks.
+When the inode number is assigned discontinuously, the maximum size of
+xino file will be the largest inode number on a branch x 4 bytes.
+Additionally, the file size is limited to LLONG_MAX or the s_maxbytes
+in filesystem's superblock (s_maxbytes may be smaller than
+LLONG_MAX). So the
+support-able largest inode number on a branch is less than
+2305843009213693950 (LLONG_MAX/4\-1).
+This is the current limitation of aufs.
+On 64bit environment, this limitation becomes more strict and the
+supported largest inode number is less than LLONG_MAX/8\-1.
+
+The xino files are always hidden, i.e. removed. So you cannot
+do `ls \-l xino_file'.
+If you enable CONFIG_DEBUG_FS, you can check these information through
+<debugfs>/aufs/<si_id>/{xib,xi[0-9]*,xigen}. xib is for the bitmap file,
+xi0 ix for the first branch, and xi1 is for the next. xigen is for the
+generation table.
+xib and xigen are in the format of,
+
+.nf
+<blocks>x<block size> <file size>
+.fi
+
+Note that a filesystem usually has a
+feature called pre-allocation, which means a number of
+blocks are allocated automatically, and then deallocated
+silently when the filesystem thinks they are unnecessary.
+You do not have to be surprised the sudden changes of the number of
+blocks, when your filesystem which xino files are placed supports the
+pre-allocation feature.
+
+The rests are hidden xino file information in the format of,
+
+.nf
+<file count>, <blocks>x<block size> <file size>
+.fi
+
+If the file count is larger than 1, it means some of your branches are
+on the same filesystem and the xino file is shared by them.
+Note that the file size may not be equal to the actual consuming blocks
+since xino file is a sparse file, i.e. a hole in a file which does not
+consume any disk blocks.
+
+Once you unmount aufs, the xino files for that aufs are totally gone.
+It means that the inode number is not permanent across umount or
+shutdown.
+
+The xino files should be created on the filesystem except NFS.
+If your first writable branch is NFS, you will need to specify xino
+file path other than NFS.
+Also if you are going to remove the branch where xino files exist or
+change the branch permission to readonly, you need to use xino option
+before del/mod the branch.
+
+The bitmap file can be truncated.
+For example, if you delete a branch which has huge number of files,
+many inode numbers will be recycled and the bitmap will be truncated
+to smaller size. Aufs does this automatically when a branch is
+deleted.
+You can truncate it anytime you like if you specify `trunc_xib' mount
+option. But when the accessed inode number was not deleted, nothing
+will be truncated.
+If you do not want to truncate it (it may be slow) when you delete a
+branch, specify `notrunc_xib' after `del' mount option.
+
+If you do not want to use xino, use noxino mount option. Use this
+option with care, since the inode number may be changed silently and
+unexpectedly anytime.
+For example,
+rmdir failure, recursive chmod/chown/etc to a large and deep directory
+or anything else.
+And some applications will not work correctly.
+.\" When the inode number has been changed, your system
+.\" can be crazy.
+If you want to change the xino default path, use xino mount option.
+
+After you add branches, the persistence of inode number may not be
+guaranteed.
+At remount time, cached but unused inodes are discarded.
+And the newly appeared inode may have different inode number at the
+next access time. The inodes in use have the persistent inode number.
+
+When aufs assigned an inode number to a file, and if you create the
+same named file on the upper branch directly, then the next time you
+access the file, aufs may assign another inode number to the file even
+if you use xino option.
+Some applications may treat the file whose inode number has been
+changed as totally different file.
+
+.\" ----------------------------------------------------------------------
+.SH Pseudo Link (hardlink over branches)
+Aufs supports `pseudo link' which is a logical hard-link over
+branches (cf. ln(1) and link(2)).
+In other words, a copied-up file by link(2) and a copied-up file which was
+hard-linked on a readonly branch filesystem.
+
+When you have files named fileA and fileB which are
+hardlinked on a readonly branch, if you write something into fileA,
+aufs copies-up fileA to a writable branch, and write(2) the originally
+requested thing to the copied-up fileA. On the writable branch,
+fileA is not hardlinked.
+But aufs remembers it was hardlinked, and handles fileB as if it existed
+on the writable branch, by referencing fileA's inode on the writable
+branch as fileB's inode.
+
+Once you unmount aufs, the plink info for that aufs kept in memory are totally
+gone.
+It means that the pseudo-link is not permanent.
+If you want to make plink permanent, try `auplink' utility just before
+one of these operations,
+unmounting your aufs,
+using `ro' or `noplink' mount option,
+deleting a branch from aufs,
+adding a branch into aufs,
+or changing your writable branch to readonly.
+
+This utility will reproduces all real hardlinks on a writable branch by linking
+them, and removes pseudo-link info in memory and temporary link on the
+writable branch.
+Since this utility access your branches directly, you cannot hide them by
+`mount \-\-bind /tmp /branch' or something.
+
+If you are willing to rebuild your aufs with the same branches later, you
+should use auplink utility before you umount your aufs.
+If you installed both of /sbin/mount.aufs and /sbin/umount.aufs, and your
+mount(8) and umount(8) support them,
+`auplink' utility will be executed automatically and flush pseudo-links.
+
+.nf
+# auplink /your/aufs/root flush
+# umount /your/aufs/root
+or
+# auplink /your/aufs/root flush
+# mount -o remount,mod:/your/writable/branch=ro /your/aufs/root
+or
+# auplink /your/aufs/root flush
+# mount -o remount,noplink /your/aufs/root
+or
+# auplink /your/aufs/root flush
+# mount -o remount,del:/your/aufs/branch /your/aufs/root
+or
+# auplink /your/aufs/root flush
+# mount -o remount,append:/your/aufs/branch /your/aufs/root
+.fi
+
+The plinks are kept both in memory and on disk. When they consumes too much
+resources on your system, you can use the `auplink' utility at anytime and
+throw away the unnecessary pseudo-links in safe.
+
+Additionally, the `auplink' utility is very useful for some security reasons.
+For example, when you have a directory whose permission flags
+are 0700, and a file who is 0644 under the 0700 directory. Usually,
+all files under the 0700 directory are private and no one else can see
+the file. But when the directory is 0711 and someone else knows the 0644
+filename, he can read the file.
+
+Basically, aufs pseudo-link feature creates a temporary link under the
+directory whose owner is root and the permission flags are 0700.
+But when the writable branch is NFS, aufs sets 0711 to the directory.
+When the 0644 file is pseudo-linked, the temporary link, of course the
+contents of the file is totally equivalent, will be created under the
+0711 directory. The filename will be generated by its inode number.
+While it is hard to know the generated filename, someone else may try peeping
+the temporary pseudo-linked file by his software tool which may try the name
+from one to MAX_INT or something.
+In this case, the 0644 file will be read unexpectedly.
+I am afraid that leaving the temporary pseudo-links can be a security hole.
+It makes sense to execute `auplink /your/aufs/root flush'
+periodically, when your writable branch is NFS.
+
+When your writable branch is not NFS, or all users are careful enough to set 0600
+to their private files, you do not have to worry about this issue.
+
+If you do not want this feature, use `noplink' mount option.
+
+.SS The behaviours of plink and noplink
+This sample shows that the `f_src_linked2' with `noplink' option cannot follow
+the link.
+
+.nf
+none on /dev/shm/u type aufs (rw,xino=/dev/shm/rw/.aufs.xino,br:/dev/shm/rw=rw:/dev/shm/ro=ro)
+$ ls -li ../r?/f_src_linked* ./f_src_linked* ./copied
+ls: ./copied: No such file or directory
+15 -rw-r--r-- 2 jro jro 2 Dec 22 11:03 ../ro/f_src_linked
+15 -rw-r--r-- 2 jro jro 2 Dec 22 11:03 ../ro/f_src_linked2
+22 -rw-r--r-- 2 jro jro 2 Dec 22 11:03 ./f_src_linked
+22 -rw-r--r-- 2 jro jro 2 Dec 22 11:03 ./f_src_linked2
+$ echo abc >> f_src_linked
+$ cp f_src_linked copied
+$ ls -li ../r?/f_src_linked* ./f_src_linked* ./copied
+15 -rw-r--r-- 2 jro jro 2 Dec 22 11:03 ../ro/f_src_linked
+15 -rw-r--r-- 2 jro jro 2 Dec 22 11:03 ../ro/f_src_linked2
+36 -rw-r--r-- 2 jro jro 6 Dec 22 11:03 ../rw/f_src_linked
+53 -rw-r--r-- 1 jro jro 6 Dec 22 11:03 ./copied
+22 -rw-r--r-- 2 jro jro 6 Dec 22 11:03 ./f_src_linked
+22 -rw-r--r-- 2 jro jro 6 Dec 22 11:03 ./f_src_linked2
+$ cmp copied f_src_linked2
+$
+
+none on /dev/shm/u type aufs (rw,xino=/dev/shm/rw/.aufs.xino,noplink,br:/dev/shm/rw=rw:/dev/shm/ro=ro)
+$ ls -li ../r?/f_src_linked* ./f_src_linked* ./copied
+ls: ./copied: No such file or directory
+17 -rw-r--r-- 2 jro jro 2 Dec 22 11:03 ../ro/f_src_linked
+17 -rw-r--r-- 2 jro jro 2 Dec 22 11:03 ../ro/f_src_linked2
+23 -rw-r--r-- 2 jro jro 2 Dec 22 11:03 ./f_src_linked
+23 -rw-r--r-- 2 jro jro 2 Dec 22 11:03 ./f_src_linked2
+$ echo abc >> f_src_linked
+$ cp f_src_linked copied
+$ ls -li ../r?/f_src_linked* ./f_src_linked* ./copied
+17 -rw-r--r-- 2 jro jro 2 Dec 22 11:03 ../ro/f_src_linked
+17 -rw-r--r-- 2 jro jro 2 Dec 22 11:03 ../ro/f_src_linked2
+36 -rw-r--r-- 1 jro jro 6 Dec 22 11:03 ../rw/f_src_linked
+53 -rw-r--r-- 1 jro jro 6 Dec 22 11:03 ./copied
+23 -rw-r--r-- 2 jro jro 6 Dec 22 11:03 ./f_src_linked
+23 -rw-r--r-- 2 jro jro 6 Dec 22 11:03 ./f_src_linked2
+$ cmp copied f_src_linked2
+cmp: EOF on f_src_linked2
+$
+.fi
+
+.\"
+.\" If you add/del a branch, or link/unlink the pseudo-linked
+.\" file on a branch
+.\" directly, aufs cannot keep the correct link count, but the status of
+.\" `pseudo-linked.'
+.\" Those files may or may not keep the file data after you unlink the
+.\" file on the branch directly, especially the case of your branch is
+.\" NFS.
+
+If you add a branch which has fileA or fileB, aufs does not follow the
+pseudo link. The file on the added branch has no relation to the same
+named file(s) on the lower branch(es).
+If you use noxino mount option, pseudo link will not work after the
+kernel shrinks the inode cache.
+
+This feature will not work for squashfs before version 3.2 since its
+inode is tricky.
+When the inode is hardlinked, squashfs inodes has the same inode
+number and correct link count, but the inode memory object is
+different. Squashfs inodes (before v3.2) are generated for each, even
+they are hardlinked.
+
+.\" ----------------------------------------------------------------------
+.SH User's Direct Branch Access (UDBA)
+UDBA means a modification to a branch filesystem manually or directly,
+e.g. bypassing aufs.
+While aufs is designed and implemented to be safe after UDBA,
+it can make yourself and your aufs confused. And some information like
+aufs inode will be incorrect.
+For example, if you rename a file on a branch directly, the file on
+aufs may
+or may not be accessible through both of old and new name.
+Because aufs caches various information about the files on
+branches. And the cache still remains after UDBA.
+
+Aufs has a mount option named `udba' which specifies the test level at
+access time whether UDBA was happened or not.
+.
+.TP
+.B udba=none
+Aufs trusts the dentry and the inode cache on the system, and never
+test about UDBA. With this option, aufs runs fastest, but it may show
+you incorrect data.
+Additionally, if you often modify a branch
+directly, aufs will not be able to trace the changes of inodes on the
+branch. It can be a cause of wrong behaviour, deadlock or anything else.
+
+It is recommended to use this option only when you are sure that
+nobody access a file on a branch.
+It might be difficult for you to achieve real `no UDBA' world when you
+cannot stop your users doing `find / \-ls' or something.
+If you really want to forbid all of your users to UDBA, here is a trick
+for it.
+With this trick, users cannot see the
+branches directly and aufs runs with no problem, except `auplink' utility.
+But if you are not familiar with aufs, this trick may make
+yourself confused.
+
+.nf
+# d=/tmp/.aufs.hide
+# mkdir $d
+# for i in $branches_you_want_to_hide
+> do
+> mount -n --bind $d $i
+> done
+.fi
+
+When you unmount the aufs, delete/modify the branch by remount, or you
+want to show the hidden branches again, unmount the bound
+/tmp/.aufs.hide.
+
+.nf
+# umount -n $branches_you_want_to_unbound
+.fi
+
+If you use FUSE filesystem as an aufs branch which supports hardlink,
+you should not set this option, since FUSE makes inode objects for
+each hardlinks (at least in linux\-2.6.23). When your FUSE filesystem
+maintains them at link/unlinking, it is equivalent
+to `direct branch access' for aufs.
+
+.
+.TP
+.B udba=reval
+Aufs tests only the existence of the file which existed. If
+the existed file was removed on the branch directly, aufs
+discard the cache about the file and
+re-lookup it. So the data will be updated.
+This test is at minimum level to keep the performance and ensure the
+existence of a file.
+This is default and aufs runs still fast.
+
+This rule leads to some unexpected situation, but I hope it is
+harmless. Those are totally depends upon cache. Here are just a few
+examples.
+.
+.RS
+.Bu
+If the file is cached as negative or
+not-existed, aufs does not test it. And the file is still handled as
+negative after a user created the file on a branch directly. If the
+file is not cached, aufs will lookup normally and find the file.
+.
+.Bu
+When the file is cached as positive or existed, and a user created the
+same named file directly on the upper branch. Aufs detects the cached
+inode of the file is still existing and will show you the old (cached)
+file which is on the lower branch.
+.
+.Bu
+When the file is cached as positive or existed, and a user renamed the
+file by rename(2) directly. Aufs detects the inode of the file is
+still existing. You may or may not see both of the old and new files.
+Todo: If aufs also tests the name, we can detect this case.
+.RE
+
+If your outer modification (UDBA) is rare and you can ignore the
+temporary and minor differences between virtual aufs world and real
+branch filesystem, then try this mount option.
+.
+.TP
+.B udba=inotify
+Aufs sets `inotify' to all the accessed directories on its branches
+and receives the event about the dir and its children. It consumes
+resources, cpu and memory. And I am afraid that the performance will be
+hurt, but it is most strict test level.
+There are some limitations of linux inotify, see also Inotify
+Limitation.
+So it is recommended to leave udba default option usually, and set it
+to inotify by remount when you need it.
+
+When a user accesses the file which was notified UDBA before, the cached data
+about the file will be discarded and aufs re-lookup it. So the data will
+be updated.
+When an error condition occurs between UDBA and aufs operation, aufs
+will return an error, including EIO.
+To use this option, you need to enable CONFIG_INOTIFY and
+CONFIG_AUFS_UDBA_INOTIFY.
+
+To rename/rmdir a directory on a branch directory may reveal the same named
+directory on the lower branch. Aufs tries re-lookuping the renamed
+directory and the revealed directory and assigning different inode
+number to them. But the inode number including their children can be a
+problem. The inode numbers will be changed silently, and
+aufs may produce a warning. If you rename a directory repeatedly and
+reveal/hide the lower directory, then aufs may confuse their inode
+numbers too. It depends upon the system cache.
+
+When you make a directory in aufs and mount other filesystem on it,
+the directory in aufs cannot be removed expectedly because it is a
+mount point. But the same named directory on the writable branch can
+be removed, if someone wants. It is just an empty directory, instead
+of a mount point.
+Aufs cannot stop such direct rmdir, but produces a warning about it.
+
+If the pseudo-linked file is hardlinked or unlinked on the branch
+directly, its inode link count in aufs may be incorrect. It is
+recommended to flush the pseudo-links by auplink script.
+
+.\" ----------------------------------------------------------------------
+.SH Linux Inotify Limitation
+Unfortunately, current inotify (linux\-2.6.18) has some limitations,
+and aufs must derive it.
+
+.SS IN_ATTRIB, updating atime
+When a file/dir on a branch is accessed directly, the inode atime (access
+time, cf. stat(2)) may or may not be updated. In some cases, inotify
+does not fire this event. So the aufs inode atime may remain old.
+
+.SS IN_ATTRIB, updating nlink
+When the link count of a file on a branch is incremented by link(2)
+directly,
+inotify fires IN_CREATE to the parent
+directory, but IN_ATTRIB to the file. So the aufs inode nlink may
+remain old.
+
+.SS IN_DELETE, removing file on NFS
+When a file on a NFS branch is deleted directly, inotify may or may
+not fire
+IN_DELETE event. It depends upon the status of dentry
+(DCACHE_NFSFS_RENAMED flag).
+In this case, the file on aufs seems still exists. Aufs and any user can see
+the file.
+
+.SS IN_IGNORED, deleted rename target
+When a file/dir on a branch is unlinked by rename(2) directly, inotify
+fires IN_IGNORED which means the inode is deleted. Actually, in some
+cases, the inode survives. For example, the rename target is linked or
+opened. In this case, inotify watch set by aufs is removed by VFS and
+inotify.
+And aufs cannot receive the events anymore. So aufs may show you
+incorrect data about the file/dir.
+
+.\" ----------------------------------------------------------------------
+.SH Virtual or Vertical Directory Block (VDIR)
+In order to provide the merged view of file listing, aufs builds
+internal directory block on memory. For readdir, aufs performs readdir()
+internally for each dir on branches, merges their entries with
+eliminating the whiteout\-ed ones, and sets it to the opened file (dir)
+object. So the file object has its entry list until it is closed. The
+entry list will be updated when the file position is zero (by
+rewinddir(3)) and becomes obsoleted.
+
+Some people may call it can be a security hole or invite DoS attack
+since the opened and once readdir\-ed dir (file object) holds its entry
+list and becomes a pressure for system memory. But I would say it is similar
+to files under /proc or /sys. The virtual files in them also holds a
+memory page (generally) while they are opened. When an idea to reduce
+memory for them is introduced, it will be applied to aufs too.
+
+The dynamically allocated memory block for the name of entries has a
+unit of \*[AUFS_RDBLK_DEF] bytes by default.
+During building dir blocks, aufs creates hash list (hashed and divided by
+\*[AUFS_RDHASH_DEF] by default) and judging whether
+the entry is whiteouted by its upper branch or already listed.
+
+These values are suitable for normal environments. But you may have
+millions of files or very long filenames under a single directory. For
+such cases, you may need to customize these values by specifying rdblk=
+and rdhash= aufs mount options.
+
+For instance, there are 97 files under my /bin, and the total name
+length is 597 bytes.
+
+.nf
+$ \\ls -1 /bin | wc
+ 97 97 597
+.fi
+
+Strictly speaking, 97 end\-of\-line codes are
+included. But it is OK since aufs VDIR also stores the name length in 1
+byte. In this case, you do not need to customize the default values. 597 bytes
+filenames will be stored in 2 VDIR memory blocks (597 <
+\*[AUFS_RDBLK_DEF] x 2).
+And 97 filenames are distributed among \*[AUFS_RDHASH_DEF] lists, so one
+list will point 4 names in average. To judge the names is whiteouted or
+not, the number of comparison will be 4. 2 memory allocations
+and 4 comparison costs low (even if the directory is opened for a long
+time). So you do not need to customize.
+
+If your directory has millions of files, the you will need to specify
+rdblk= and rdhash=.
+
+.nf
+$ ls -U /mnt/rotating-rust | wc -l
+1382438
+.fi
+
+In this case, assuming the average length of filenames is 6, in order to
+get better time performance I would
+recommend to set $((128*1024)) or $((64*1024)) for rdblk, and
+$((8*1024)) or $((4*1024)) for rdhash.
+You can change these values of the active aufs mount by "mount -o
+remount".
+
+This customization is not for
+reducing the memory space, but for reducing time for the number of memory
+allocation and the name comparison. The larger value is faster, in
+general. Of course, you will need system memory. This is a generic
+"time\-vs\-space" problem.
+
+.\" ----------------------------------------------------------------------
+.SH Copy On Write, or aufs internal copyup and copydown
+Every stackable filesystem which implements copy\-on\-write supports the
+copyup feature. The feature is to copy a file/dir from the lower branch
+to the upper internally. When you have one readonly branch and one
+upper writable branch, and you append a string to a file which exists on
+the readonly branch, then aufs will copy the file from the readonly
+branch to the writable branch with its directory hierarchy. It means one
+write(2) involves several logical/internal mkdir(2), creat(2), read(2),
+write(2) and close(2) systemcalls
+before the actual expected write(2) is performed. Sometimes it may take
+a long time, particularly when the file is very large.
+If CONFIG_AUFS_DEBUG is enabled, aufs produces a message saying `copying
+a large file.'
+
+You may see the message when you change the xino file path or
+truncate the xino/xib files. Sometimes those files can be large and may
+take a long time to handle them.
+
+.\" ----------------------------------------------------------------------
+.SH Policies to Select One among Multiple Writable Branches
+Aufs has some policies to select one among multiple writable branches
+when you are going to write/modify something. There are two kinds of
+policies, one is for newly create something and the other is for
+internal copy-up.
+You can select them by specifying mount option `create=CREATE_POLICY'
+or `cpup=COPYUP_POLICY.'
+These policies have no meaning when you have only one writable
+branch. If there is some meaning, it must hurt the performance.
+
+.SS Exceptions for Policies
+In every cases below, even if the policy says that the branch where a
+new file should be created is /rw2, the file will be created on /rw1.
+.
+.Bu
+If there is a readonly branch with `wh' attribute above the
+policy-selected branch and the parent dir is marked as opaque,
+or the target (creating) file is whiteouted on the ro+wh branch, then
+the policy will be ignored and the target file will be created on the
+nearest upper writable branch than the ro+wh branch.
+.RS
+.nf
+/aufs = /rw1 + /ro+wh/diropq + /rw2
+/aufs = /rw1 + /ro+wh/wh.tgt + /rw2
+.fi
+.RE
+.
+.Bu
+If there is a writable branch above the policy-selected branch and the
+parent dir is marked as opaque or the target file is whiteouted on the
+branch, then the policy will be ignored and the target file will be
+created on the highest one among the upper writable branches who has
+diropq or whiteout. In case of whiteout, aufs removes it as usual.
+.RS
+.nf
+/aufs = /rw1/diropq + /rw2
+/aufs = /rw1/wh.tgt + /rw2
+.fi
+.RE
+.
+.Bu
+link(2) and rename(2) systemcalls are exceptions in every policy.
+They try selecting the branch where the source exists as possible since
+copyup a large file will take long time. If it can't be, ie. the
+branch where the source exists is readonly, then they will follow the
+copyup policy.
+.
+.Bu
+There is an exception for rename(2) when the target exists.
+If the rename target exists, aufs compares the index of the branches
+where the source and the target are existing and selects the higher
+one. If the selected branch is readonly, then aufs follows the copyup
+policy.
+
+.SS Policies for Creating
+.
+.TP
+.B create=tdp | top\-down\-parent
+Selects the highest writable branch where the parent dir exists. If
+the parent dir does not exist on a writable branch, then the internal
+copyup will happen. The policy for this copyup is always `bottom-up.'
+This is the default policy.
+.
+.TP
+.B create=rr | round\-robin
+Selects a writable branch in round robin. When you have two writable
+branches and creates 10 new files, 5 files will be created for each
+branch.
+mkdir(2) systemcall is an exception. When you create 10 new directories,
+all are created on the same branch.
+.
+.TP
+.B create=mfs[:second] | most\-free\-space[:second]
+Selects a writable branch which has most free space. In order to keep
+the performance, you can specify the duration (`second') which makes
+aufs hold the index of last selected writable branch until the
+specified seconds expires. The first time you create something in aufs
+after the specified seconds expired, aufs checks the amount of free
+space of all writable branches by internal statfs call
+and the held branch index will be updated.
+The default value is \*[AUFS_MFS_SECOND_DEF] seconds.
+.
+.TP
+.B create=mfsrr:low[:second]
+Selects a writable branch in most-free-space mode first, and then
+round-robin mode. If the selected branch has less free space than the
+specified value `low' in bytes, then aufs re-tries in round-robin mode.
+.\" `G', `M' and `K' (case insensitive) can be followed after `low.' Or
+Try an arithmetic expansion of shell which is defined by POSIX.
+For example, $((10 * 1024 * 1024)) for 10M.
+You can also specify the duration (`second') which is equivalent to
+the `mfs' mode.
+.
+.TP
+.B create=pmfs[:second]
+Selects a writable branch where the parent dir exists, such as tdp
+mode. When the parent dir exists on multiple writable branches, aufs
+selects the one which has most free space, such as mfs mode.
+
+.SS Policies for Copy-Up
+.
+.TP
+.B cpup=tdp | top\-down\-parent
+Equivalent to the same named policy for create.
+This is the default policy.
+.
+.TP
+.B cpup=bup | bottom\-up\-parent
+Selects the writable branch where the parent dir exists and the branch
+is nearest upper one from the copyup-source.
+.
+.TP
+.B cpup=bu | bottom\-up
+Selects the nearest upper writable branch from the copyup-source,
+regardless the existence of the parent dir.
+
+.\" ----------------------------------------------------------------------
+.SH Exporting Aufs via NFS
+Aufs is supporting NFS-exporting.
+Since aufs has no actual block device, you need to add NFS `fsid' option at
+exporting. Refer to the manual of NFS about the detail of this option.
+
+There are some limitations or requirements.
+.RS
+.Bu
+The branch filesystem must support NFS-exporting.
+.Bu
+NFSv2 is not supported. When you mount the exported aufs from your NFS
+client, you will need to some NFS options like v3 or nfsvers=3,
+especially if it is nfsroot.
+.Bu
+If the size of the NFS file handle on your branch filesystem is large,
+aufs will
+not be able to handle it. The maximum size of NFSv3 file
+handle for a filesystem is 64 bytes. Aufs uses 24 bytes for 32bit
+system, plus 12 bytes for 64bit system. The rest is a room for a file
+handle of a branch filesystem.
+.Bu
+The External Inode Number Bitmap, Translation Table and Generation Table
+(xino) is
+required since NFS file
+handle is based upon inode number. The mount option `xino' is enabled
+by default.
+The external inode generation table and its debugfs entry
+(<debugfs>/aufs/si_*/xigen) is created when CONFIG_AUFS_EXPORT is
+enabled even if you don't export aufs actually.
+The size of the external inode generation table grows only, never be
+truncated. You might need to pay attention to the free space of the
+filesystem where xino files are placed. By default, it is the first
+writable branch.
+.Bu
+The branch filesystems must be accessible, which means `not hidden.'
+It means you need to `mount \-\-move' when you use initramfs and
+switch_root(8), or chroot(8).
+.RE
+
+.\" ----------------------------------------------------------------------
+.SH Dentry and Inode Caches
+If you want to clear caches on your system, there are several tricks
+for that. If your system ram is low,
+try `find /large/dir \-ls > /dev/null'.
+It will read many inodes and dentries and cache them. Then old caches will be
+discarded.
+But when you have large ram or you do not have such large
+directory, it is not effective.
+
+If you want to discard cache within a certain filesystem,
+try `mount \-o remount /your/mntpnt'. Some filesystem may return an error of
+EINVAL or something, but VFS discards the unused dentry/inode caches on the
+specified filesystem.
+
+.\" ----------------------------------------------------------------------
+.SH Compatible/Incompatible with Unionfs Version 1.x Series
+If you compile aufs with \-DCONFIG_AUFS_COMPAT, dirs= option and =nfsro
+branch permission flag are available. They are interpreted as
+br: option and =ro flags respectively.
+ `debug', `delete', `imap' options are ignored silently. When you
+compile aufs without \-DCONFIG_AUFS_COMPAT, these three options are
+also ignored, but a warning message is issued.
+
+Ignoring `delete' option, and to keep filesystem consistency, aufs tries
+writing something to only one branch in a single systemcall. It means
+aufs may copyup even if the copyup-src branch is specified as writable.
+For example, you have two writable branches and a large regular file
+on the lower writable branch. When you issue rename(2) to the file on aufs,
+aufs may copyup it to the upper writable branch.
+If this behaviour is not what you want, then you should rename(2) it
+on the lower branch directly.
+
+And there is a simple shell
+script `unionctl' under sample subdirectory, which is compatible with
+unionctl(8) in
+Unionfs Version 1.x series, except \-\-query action.
+This script executes mount(8) with `remount' option and uses
+add/del/mod aufs mount options.
+If you are familiar with Unionfs Version 1.x series and want to use unionctl(8), you can
+try this script instead of using mount \-o remount,... directly.
+Aufs does not support ioctl(2) interface.
+This script is highly depending upon mount(8) in
+util\-linux\-2.12p package, and you need to mount /proc to use this script.
+If your mount(8) version differs, you can try modifying this
+script. It is very easy.
+The unionctl script is just for a sample usage of aufs remount
+interface.
+
+Aufs uses the external inode number bitmap and translation table by
+default.
+
+The default branch permission for the first branch is `rw', and the
+rest is `ro.'
+
+The whiteout is for hiding files on lower branches. Also it is applied
+to stop readdir going lower branches.
+The latter case is called `opaque directory.' Any
+whiteout is an empty file, it means whiteout is just an mark.
+In the case of hiding lower files, the name of whiteout is
+`\*[AUFS_WH_PFX]<filename>.'
+And in the case of stopping readdir, the name is
+`\*[AUFS_WH_PFX]\*[AUFS_WH_PFX].opq' or
+`\*[AUFS_WH_PFX]__dir_opaque.' The name depends upon your compile
+configuration
+CONFIG_AUFS_COMPAT.
+.\" All of newly created or renamed directory will be opaque.
+All whiteouts are hardlinked,
+including `<writable branch top dir>/\*[AUFS_WH_BASE].'
+
+The hardlink on an ordinary (disk based) filesystem does not
+consume inode resource newly. But in linux tmpfs, the number of free
+inodes will be decremented by link(2). It is recommended to specify
+nr_inodes option to your tmpfs if you meet ENOSPC. Use this option
+after checking by `df \-i.'
+
+When you rmdir or rename-to the dir who has a number of whiteouts,
+aufs rename the dir to the temporary whiteouted-name like
+`\*[AUFS_WH_PFX]<dir>.<random hex>.' Then remove it after actual operation.
+cf. mount option `dirwh.'
+
+.\" ----------------------------------------------------------------------
+.SH Incompatible with an Ordinary Filesystem
+stat(2) returns the inode info from the first existence inode among
+the branches, except the directory link count.
+Aufs computes the directory link count larger than the exact value usually, in
+order to keep UNIX filesystem semantics, or in order to shut find(1) mouth up.
+The size of a directory may be wrong too, but it has to do no harm.
+The timestamp of a directory will not be updated when a file is
+created or removed under it, and it was done on a lower branch.
+
+The test for permission bits has two cases. One is for a directory,
+and the other is for a non-directory. In the case of a directory, aufs
+checks the permission bits of all existing directories. It means you
+need the correct privilege for the directories including the lower
+branches.
+The test for a non-directory is more simple. It checks only the
+topmost inode.
+
+statfs(2) returns the information of the first branch info except
+namelen when `nosum' is specified (the default). The namelen is
+decreased by the whiteout prefix length. And the block size may differ
+from st_blksize which is obtained by stat(2).
+
+Remember, seekdir(3) and telldir(3) are not defined in POSIX. They may
+not work as you expect. Try rewinddir(3) or re-open the dir.
+
+The whiteout prefix (\*[AUFS_WH_PFX]) is reserved on all branches. Users should
+not handle the filename begins with this prefix.
+In order to future whiteout, the maximum filename length is limited by
+the longest value \- \*[AUFS_WH_PFX_LEN]. It may be a violation of POSIX.
+
+If you dislike the difference between the aufs entries in /etc/mtab
+and /proc/mounts, and if you are using mount(8) in util\-linux package,
+then try ./mount.aufs utility. Copy the script to /sbin/mount.aufs.
+This simple utility tries updating
+/etc/mtab. If you do not care about /etc/mtab, you can ignore this
+utility.
+Remember this utility is highly depending upon mount(8) in
+util\-linux\-2.12p package, and you need to mount /proc.
+
+Since aufs uses its own inode and dentry, your system may cache huge
+number of inodes and dentries. It can be as twice as all of the files
+in your union.
+It means that unmounting or remounting readonly at shutdown time may
+take a long time, since mount(2) in VFS tries freeing all of the cache
+on the target filesystem.
+
+When you open a directory, aufs will open several directories
+internally.
+It means you may reach the limit of the number of file descriptor.
+And when the lower directory cannot be opened, aufs will close all the
+opened upper directories and return an error.
+
+The sub-mount under the branch
+of local filesystem
+is ignored.
+For example, if you have mount another filesystem on
+/branch/another/mntpnt, the files under `mntpnt' will be ignored by aufs.
+It is recommended to mount the sub-mount under the mounted aufs.
+For example,
+
+.nf
+# sudo mount /dev/sdaXX /ro_branch
+# d=another/mntpnt
+# sudo mount /dev/sdbXX /ro_branch/$d
+# mkdir -p /rw_branch/$d
+# sudo mount -t aufs -o br:/rw_branch:/ro_branch none /aufs
+# sudo mount -t aufs -o br:/rw_branch/${d}:/ro_branch/${d} none /aufs/another/$d
+.fi
+
+There are several characters which are not allowed to use in a branch
+directory path and xino filename. See detail in Branch Syntax and Mount
+Option.
+
+The file-lock which means fcntl(2) with F_SETLK, F_SETLKW or F_GETLK, flock(2)
+and lockf(3), is applied to virtual aufs file only, not to the file on a
+branch. It means you can break the lock by accessing a branch directly.
+TODO: check `security' to hook locks, as inotify does.
+
+The I/O to the named pipe or local socket are not handled by aufs, even
+if it exists in aufs. After the reader and the writer established their
+connection if the pipe/socket are copied-up, they keep using the old one
+instead of the copied-up one.
+
+The fsync(2) and fdatasync(2) systemcalls return 0 which means success, even
+if the given file descriptor is not opened for writing.
+I am afraid this behaviour may violate some standards. Checking the
+behaviour of fsync(2) on ext2, aufs decided to return success.
+
+If you want to use disk-quota, you should set it up to your writable
+branch since aufs does not have its own block device.
+
+When your aufs is the root directory of your system, and your system
+tells you some of the filesystem were not unmounted cleanly, try these
+procedure when you shutdown your system.
+.nf
+# mount -no remount,ro /
+# for i in $writable_branches
+# do mount -no remount,ro $i
+# done
+.fi
+If your xino file is on a hard drive, you also need to specify
+`noxino' option or `xino=/your/tmpfs/xino' at remounting root
+directory.
+
+To rename(2) directory may return EXDEV even if both of src and tgt
+are on the same aufs. When the rename-src dir exists on multiple
+branches and the lower dir has child(ren), aufs has to copyup all his
+children. It can be recursive copyup. Current aufs does not support
+such huge copyup operation at one time in kernel space, instead
+produces a warning and returns EXDEV.
+Generally, mv(1) detects this error and tries mkdir(2) and
+rename(2) or copy/unlink recursively. So the result is harmless.
+If your application which issues rename(2) for a directory does not
+support EXDEV, it will not work on aufs.
+Also this specification is applied to the case when the src directory
+exists on the lower readonly branch and it has child(ren).
+
+If a sudden accident such like a power failure happens during aufs is
+performing, and regular fsck for branch filesystems is completed after
+the disaster, you need to extra fsck for aufs writable branches. It is
+necessary to check whether the whiteout remains incorrectly or not,
+eg. the real filename and the whiteout for it under the same parent
+directory. If such whiteout remains, aufs cannot handle the file
+correctly.
+To check the consistency from the aufs' point of view, you can use a
+simple shell script called /sbin/auchk. Its purpose is a fsck tool for
+aufs, and it checks the illegal whiteout, the remained
+pseudo-links and the remained aufs-temp files. If they are found, the
+utility reports you and asks whether to delete or not.
+It is recommended to execute /sbin/auchk for every writable branch
+filesystem before mounting aufs if the system experienced crash.
+
+
+.\" ----------------------------------------------------------------------
+.SH EXAMPLES
+The mount options are interpreted from left to right at remount-time.
+These examples
+shows how the options are handled. (assuming /sbin/mount.aufs was
+installed)
+
+.nf
+# mount -v -t aufs br:/day0:/base none /u
+none on /u type aufs (rw,xino=/day0/.aufs.xino,br:/day0=rw:/base=ro)
+# mount -v -o remount,\\
+ prepend:/day1,\\
+ xino=/day1/xino,\\
+ mod:/day0=ro,\\
+ del:/day0 \\
+ /u
+none on /u type aufs (rw,xino=/day1/xino,br:/day1=rw:/base=ro)
+.fi
+
+.nf
+# mount -t aufs br:/rw none /u
+# mount -o remount,append:/ro /u
+different uid/gid/permission, /ro
+# mount -o remount,del:/ro /u
+# mount -o remount,nowarn_perm,append:/ro /u
+#
+(there is no warning)
+.fi
+
+.\" If you want to expand your filesystem size, aufs may help you by
+.\" adding an writable branch. Since aufs supports multiple writable
+.\" branches, the old writable branch can be being writable, if you want.
+.\" In this example, any modifications to the files under /ro branch will
+.\" be copied-up to /new, but modifications to the files under /rw branch
+.\" will not.
+.\" And the next example shows the modifications to the files under /rw branch
+.\" will be copied-up to /new/a.
+.\"
+.\" Todo: test multiple writable branches policy. cpup=nearest, cpup=exist_parent.
+.\"
+.\" .nf
+.\" # mount -v -t aufs br:/rw:/ro none /u
+.\" none on /u type aufs (rw,xino=/rw/.aufs.xino,br:/rw=rw:/ro=ro)
+.\" # mkfs /new
+.\" # mount -v -o remount,add:1:/new=rw /u
+.\" none on /u type aufs (rw,xino=/rw/.aufs.xino,br:/rw=rw:/new=rw:/ro=ro)
+.\" .fi
+.\"
+.\" .nf
+.\" # mount -v -t aufs br:/rw:/ro none /u
+.\" none on /u type aufs (rw,xino=/rw/.aufs.xino,br:/rw=rw:/ro=ro)
+.\" # mkfs /new
+.\" # mkdir /new/a new/b
+.\" # mount -v -o remount,add:1:/new/b=rw,prepend:/new/a,mod:/rw=ro /u
+.\" none on /u type aufs (rw,xino=/rw/.aufs.xino,br:/new/a=rw:/rw=ro:/new/b=rw:/ro=ro)
+.\" .fi
+
+When you use aufs as root filesystem, it is recommended to consider to
+exclude some directories. For example, /tmp and /var/log are not need
+to stack in many cases. They do not usually need to copyup or to whiteout.
+Also the swapfile on aufs (a regular file, not a block device) is not
+supported.
+In order to exclude the specific dir from aufs, try bind mounting.
+
+And there is a good sample which is for network booted diskless machines. See
+sample/ in detail.
+
+.\" ----------------------------------------------------------------------
+.SH DIAGNOSTICS
+When you add a branch to your union, aufs may warn you about the
+privilege or security of the branch, which is the permission bits,
+owner and group of the top directory of the branch.
+For example, when your upper writable branch has a world writable top
+directory,
+a malicious user can create any files on the writable branch directly,
+like copyup and modify manually. I am afraid it can be a security
+issue.
+
+When you mount or remount your union without \-o ro common mount option
+and without writable branch, aufs will warn you that the first branch
+should be writable.
+
+.\" It is discouraged to set both of `udba' and `noxino' mount options. In
+.\" this case the inode number under aufs will always be changed and may
+.\" reach the end of inode number which is a maximum of unsigned long. If
+.\" the inode number reaches the end, aufs will return EIO repeatedly.
+
+When you set udba other than inotify and change something on your
+branch filesystem directly, later aufs may detect some mismatches to
+its cache. If it is a critical mismatch, aufs returns EIO.
+
+When an error occurs in aufs, aufs prints the kernel message with
+`errno.' The priority of the message (log level) is ERR or WARNING which
+depends upon the message itself.
+You can convert the `errno' into the error message by perror(3),
+strerror(3) or something.
+For example, the `errno' in the message `I/O Error, write failed (\-28)'
+is 28 which means ENOSPC or `No space left on device.'
+
+When CONFIG_AUFS_BR_RAMFS is enabled, you can specify ramfs as an aufs
+branch. Since ramfs is simple, it does not set the maximum link count
+originally. In aufs, it is very dangerous, particularly for
+whiteouts. Finally aufs sets the maximum link count for ramfs. The
+value is 32000 which is borrowed from ext2.
+
+
+.\" .SH Current Limitation
+.
+.\" ----------------------------------------------------------------------
+.\" SYNOPSIS
+.\" briefly describes the command or function's interface. For commands, this
+.\" shows the syntax of the command and its arguments (including options); bold-
+.\" face is used for as-is text and italics are used to indicate replaceable
+.\" arguments. Brackets ([]) surround optional arguments, vertical bars (|) sep-
+.\" arate choices, and ellipses (...) can be repeated. For functions, it shows
+.\" any required data declarations or #include directives, followed by the func-
+.\" tion declaration.
+.
+.\" DESCRIPTION
+.\" gives an explanation of what the command, function, or format does. Discuss
+.\" how it interacts with files and standard input, and what it produces on
+.\" standard output or standard error. Omit internals and implementation
+.\" details unless they're critical for understanding the interface. Describe
+.\" the usual case; for information on options use the OPTIONS section. If
+.\" there is some kind of input grammar or complex set of subcommands, consider
+.\" describing them in a separate USAGE section (and just place an overview in
+.\" the DESCRIPTION section).
+.
+.\" RETURN VALUE
+.\" gives a list of the values the library routine will return to the caller and
+.\" the conditions that cause these values to be returned.
+.
+.\" EXIT STATUS
+.\" lists the possible exit status values or a program and the conditions that
+.\" cause these values to be returned.
+.
+.\" USAGE
+.\" describes the grammar of any sublanguage this implements.
+.
+.\" FILES
+.\" lists the files the program or function uses, such as configuration files,
+.\" startup files, and files the program directly operates on. Give the full
+.\" pathname of these files, and use the installation process to modify the
+.\" directory part to match user preferences. For many programs, the default
+.\" installation location is in /usr/local, so your base manual page should use
+.\" /usr/local as the base.
+.
+.\" ENVIRONMENT
+.\" lists all environment variables that affect your program or function and how
+.\" they affect it.
+.
+.\" SECURITY
+.\" discusses security issues and implications. Warn about configurations or
+.\" environments that should be avoided, commands that may have security impli-
+.\" cations, and so on, especially if they aren't obvious. Discussing security
+.\" in a separate section isn't necessary; if it's easier to understand, place
+.\" security information in the other sections (such as the DESCRIPTION or USAGE
+.\" section). However, please include security information somewhere!
+.
+.\" CONFORMING TO
+.\" describes any standards or conventions this implements.
+.
+.\" NOTES
+.\" provides miscellaneous notes.
+.
+.\" BUGS
+.\" lists limitations, known defects or inconveniences, and other questionable
+.\" activities.
+
+.SH COPYRIGHT
+Copyright \(co 2005\-2009 Junjiro R. Okajima
+
+.SH AUTHOR
+Junjiro R. Okajima
+
+.\" SEE ALSO
+.\" lists related man pages in alphabetical order, possibly followed by other
+.\" related pages or documents. Conventionally this is the last section.
diff --git a/package/aufs2-util/src/aufs.shlib b/package/aufs2-util/src/aufs.shlib
new file mode 100644
index 000000000..7aa07665c
--- /dev/null
+++ b/package/aufs2-util/src/aufs.shlib
@@ -0,0 +1,83 @@
+#
+# Copyright (C) 2005-2009 Junjiro Okajima
+#
+# This program, aufs is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+# library functions for aufs shell scripts
+
+# path in canonical representation
+SetDir() # var dir
+{
+ cd "$2"
+ eval "$1=\"$PWD\""
+ cd "$OLDPWD"
+}
+
+# escape the unprintable characters, mainly for grep-ping /proc/mounts
+Esc() # [-e]
+{
+ sed -r -e '
+ s/\\/\\134/g
+ s/$/\\012/
+ ' |
+ tr -d '\n' |
+ sed -r -e '
+ s/ /\\040/g
+ s/\t/\\011/g
+ s/\r/\\015/g
+ s/\\012$//
+ ' |
+ { test $# -eq 1 &&
+ test "$1" = "-e" &&
+ sed -r -e 's/\\/\\\\/g' ||
+ cat; }
+ echo
+}
+
+# find a mount-entry by its mount-point
+FindMntEnt() # mntpnt
+{
+ proc_mounts=/proc/self/mounts
+ test ! -e $proc_mounts && proc_mounts=/proc/$$/mounts
+ test ! -e $proc_mounts && proc_mounts=/proc/mounts
+ fgrep \ $(echo "$1" | Esc)\ aufs\ $proc_mounts |
+ tail -n 1
+}
+
+# current mount options
+MntOpts() # mntpnt
+{
+ FindMntEnt "$1" |
+ cut -f4 -d' '
+}
+
+########################################
+
+AuDebug() # 1 | 0 [sec]
+{
+ test $1 -eq 0 && set +x
+ aufs_debug=/sys/module/aufs/parameters/debug
+ if [ -f $aufs_debug ]
+ then
+ echo $1 | sudo dd of=$aufs_debug 2> /dev/null
+ test $# -eq 2 && sleep $2
+ fi
+ test $1 -eq 1 && set -x
+ true
+}
+
+# Local variables: ;
+# mode: text;
+# End: ;
diff --git a/package/aufs2-util/src/auplink.c b/package/aufs2-util/src/auplink.c
new file mode 100644
index 000000000..1b48bea51
--- /dev/null
+++ b/package/aufs2-util/src/auplink.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2005-2009 Junjiro Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "au_util.h"
+
+static void usage(char *me)
+{
+ fprintf(stderr,
+ "usage: %s aufs_mount_point list|cpup|flush\n"
+ "'list' shows the pseudo-linked inode numbers and filenames.\n"
+ "'cpup' copies-up all pseudo-link to the writeble branch.\n"
+ "'flush' calls 'cpup', and then 'mount -o remount,clean_plink=inum'\n"
+ "and remove the whiteouted plink.\n", me);
+ exit(EINVAL);
+}
+
+int main(int argc, char *argv[])
+{
+ int err, cmd;
+ char *cwd;
+
+ if (argc != 3)
+ usage(argv[0]);
+
+ if (!strcmp(argv[2], "flush"))
+ cmd = AuPlink_FLUSH;
+ else if (!strcmp(argv[2], "list"))
+ cmd = AuPlink_LIST;
+ else if (!strcmp(argv[2], "cpup"))
+ cmd = AuPlink_CPUP;
+ else {
+ errno = EINVAL;
+ AuFin("%s", argv[2]);
+ cmd = 0; /* never reach here */
+ }
+
+ err = chdir(argv[1]);
+ if (err)
+ AuFin("chdir");
+ cwd = getcwd(NULL, 0); /* glibc */
+ if (!cwd)
+ AuFin("getcwd");
+ return au_plink(cwd, cmd, 1, 0);
+}
diff --git a/package/aufs2-util/src/br.c b/package/aufs2-util/src/br.c
new file mode 100644
index 000000000..6451c120e
--- /dev/null
+++ b/package/aufs2-util/src/br.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2005-2009 Junjiro Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define _GNU_SOURCE /* strndup */
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <mntent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <linux/aufs_type.h>
+#include "au_util.h"
+
+static int by_opts(char ***br, int *nbr, char *bropt)
+{
+ char *p, **a;
+ int l;
+
+ /* bropts is placed at the end of mnt_opts */
+ errno = EINVAL;
+ //puts(bropt);
+ if (strchr(bropt, ','))
+ AuFin("%s", bropt);
+
+ l = strlen(bropt);
+ p = malloc(l + 2);
+ if (!p)
+ AuFin("malloc");
+ memcpy(p, bropt, l + 1);
+ bropt = p;
+ bropt[l + 1] = 0; /* end marker */
+
+ *nbr = 1;
+ while (1) {
+ p = strchr(p + 1, ':');
+ if (!p)
+ break;
+ *p = 0;
+ (*nbr)++;
+ }
+
+ a = malloc(sizeof(a) * (*nbr + 1));
+ if (!a)
+ AuFin("malloc");
+
+ *br = a;
+ *a++ = bropt;
+ p = bropt;
+ while (*p) {
+ p += strlen(p) + 1;
+ *a++ = p;
+ }
+ *--a = NULL;
+ /* don't free bropt */
+
+ return 0;
+}
+
+#ifdef DEBUG
+#define SiPathPrefix "/tmp/aufs/si_"
+#define BufSiz 4
+#else
+#define SiPathPrefix "/sys/fs/aufs/si_"
+#define BufSiz BUFSIZ
+#endif
+
+static int by_sysfs(char ***br, int *nbr, char *siopt)
+{
+ int err, i, l, sz;
+ char buf[BufSiz], path[] = SiPathPrefix "1234567890123456/br32767";
+ char *p, *end, **a, *q;
+ FILE *fp;
+
+ errno = EINVAL;
+ end = strchr(siopt, ',');
+ if (end)
+ i = end - siopt;
+ else
+ i = strlen(siopt);
+
+ strncpy(path + sizeof(SiPathPrefix) - 1, siopt, i);
+ p = path + sizeof(SiPathPrefix) - 1 + i;
+ strcpy(p, "/br");
+ p += 3; /* "/br" */
+ *nbr = 0;
+ err = 0;
+ while (!err) {
+ sprintf(p, "%d", (*nbr)++);
+ err = access(path, F_OK);
+ }
+
+ a = malloc(sizeof(*br) * *nbr);
+ if (!a)
+ AuFin("malloc");
+
+ (*nbr)--;
+ *br = a;
+ for (i = 0; i < *nbr; i++) {
+ sprintf(p, "%d", i);
+ fp = fopen(path, "r");
+ if (!fp)
+ AuFin("%s", path);
+ if (fgets(buf, sizeof(buf), fp) != buf)
+ AuFin("%s", path);
+ l = strlen(buf);
+ if (l < 1)
+ AuFin("internal error, %d", l);
+
+ q = strndup(buf, l - 1);
+ if (buf[l - 1] != '\n') {
+ /* a branch path with crazy length */
+ /* stat(2) for sysfs is meaningless */
+ sz = sizeof(buf);
+ do {
+ free(q);
+ sz <<= 1;
+ q = malloc(sz);
+ if (!q)
+ AuFin("malloc");
+ rewind(fp);
+ if (fgets(q, sz, fp) != q)
+ AuFin("%s", path);
+ l = strlen(q);
+ } while (q[l - 1] != '\n');
+ q[l - 1] = 0;
+ }
+
+ *a++ = q;
+ /* don't free q */
+ fclose(fp); /* ignore */
+ }
+ *a = NULL;
+
+ return 0;
+}
+
+#define BrOpt ",br:"
+#define SiOpt "si"
+int au_br(char ***br, int *nbr, struct mntent *ent)
+{
+ char *p;
+
+ *nbr = 0;
+ p = strstr(ent->mnt_opts, BrOpt);
+ if (p)
+ return by_opts(br, nbr, p + sizeof(BrOpt) - 1);
+ p = hasmntopt(ent, SiOpt);
+ if (p)
+ return by_sysfs(br, nbr, p + sizeof(SiOpt));
+
+ /* broken opts */
+ AuFin("internal error, %s", ent->mnt_opts);
+ return -1; /* never reach here */
+}
diff --git a/package/aufs2-util/src/c2sh.c b/package/aufs2-util/src/c2sh.c
new file mode 100644
index 000000000..80ef044a1
--- /dev/null
+++ b/package/aufs2-util/src/c2sh.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2005-2009 Junjiro Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <linux/aufs_type.h>
+
+#define AUFS_WH_PFX2 AUFS_WH_PFX AUFS_WH_PFX
+
+int
+main(int argc, char *argv[])
+{
+#define p(m, v, fmt) printf("%s=" fmt "\n", m, v)
+#define pstr(m) p(#m, m, "%s")
+#define pint(m) p(#m, m, "%d")
+ pstr(AUFS_VERSION);
+ pint(AUFS_SUPER_MAGIC);
+ printf("AUFS_SUPER_MAGIC_HEX=0x%x\n", AUFS_SUPER_MAGIC);
+ pstr(AUFS_WH_PFX);
+ pstr(AUFS_WH_PFX2);
+ pstr(AUFS_WKQ_NAME);
+ pstr(AUFS_WH_DIROPQ);
+ pstr(AUFS_WH_BASE);
+ pstr(AUFS_WH_PLINKDIR);
+ pstr(AUFS_WH_ORPHDIR);
+ //pint(AUFS_BRANCH_MAX);
+ return 0;
+}
diff --git a/package/aufs2-util/src/c2tmac.c b/package/aufs2-util/src/c2tmac.c
new file mode 100644
index 000000000..0018763b4
--- /dev/null
+++ b/package/aufs2-util/src/c2tmac.c
@@ -0,0 +1,44 @@
+
+/*
+ * Copyright (C) 2005-2009 Junjiro Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <linux/aufs_type.h>
+
+int
+main(int argc, char *argv[])
+{
+#define p(m, v, fmt) printf(".ds %s " fmt "\n", m, v)
+#define pstr(m) p(#m, m, "%s")
+#define pint(m) p(#m, m, "%d")
+ pstr(AUFS_VERSION);
+ pstr(AUFS_XINO_FNAME);
+ pstr(AUFS_XINO_DEFPATH);
+ pint(AUFS_DIRWH_DEF);
+ pstr(AUFS_WH_PFX);
+ pint(AUFS_WH_PFX_LEN);
+ pstr(AUFS_WKQ_NAME);
+ pint(AUFS_NWKQ_DEF);
+ pstr(AUFS_WH_DIROPQ);
+ pstr(AUFS_WH_BASE);
+ pstr(AUFS_WH_PLINKDIR);
+ pint(AUFS_MFS_SECOND_DEF);
+ pint(AUFS_RDBLK_DEF);
+ pint(AUFS_RDHASH_DEF);
+ return 0;
+}
diff --git a/package/aufs2-util/src/compat.h b/package/aufs2-util/src/compat.h
new file mode 100644
index 000000000..ddb436e7e
--- /dev/null
+++ b/package/aufs2-util/src/compat.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2009 Junjiro Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __compat_h__
+#define __compat_h__
+
+#ifndef AT_SYMLINK_NOFOLLOW
+#define AT_SYMLINK_NOFOLLOW 0x100 /* Do not follow symbolic links. */
+
+#define __KERNEL__
+#include <unistd.h>
+#include <asm/unistd.h>
+#define fstatat fstatat64
+int fstatat(int dirfd, const char *path, struct stat *buf, int flags);
+_syscall4(int, fstatat64, int, _dirfd, const char *, path, struct stat *, buf, int, flags);
+#undef __KERNEL__
+#endif
+
+#endif /* __compat_h__ */
diff --git a/package/aufs2-util/src/mount.aufs.c b/package/aufs2-util/src/mount.aufs.c
new file mode 100644
index 000000000..d801cfd3c
--- /dev/null
+++ b/package/aufs2-util/src/mount.aufs.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2005-2009 Junjiro Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * The main purpose of this script is updating /etc/mtab and calling auplilnk.
+ * This behaviour is highly depending on mount(8) in util-linux package.
+ */
+
+#define _XOPEN_SOURCE 500 /* getsubopt */
+#define _BSD_SOURCE /* dirfd */
+
+#include <sys/types.h>
+#include <dirent.h>
+#include <mntent.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wait.h>
+
+#include <linux/aufs_type.h>
+#include "au_util.h"
+
+enum { Remount, Bind, Fake, Update, Verbose, AuFlush, LastOpt };
+static void test_opts(char opts[], unsigned char flags[])
+{
+ int c;
+ char *p, *o, *val, *pat[] = {
+ [Remount] = "remount",
+ [Bind] = "bind",
+ NULL
+ };
+
+ o = strdup(opts);
+ if (!o)
+ AuFin("stdup");
+
+ p = o;
+ while (*p) {
+ c = getsubopt(&p, pat, &val);
+ switch (c) {
+ case Remount:
+ flags[Remount] = 1;
+ break;
+ case Bind:
+ flags[Bind] = 1;
+ break;
+ }
+ }
+ free(o);
+}
+
+static int test_flush(char opts[])
+{
+ int err, i;
+ regex_t preg;
+ char *p, *o;
+ const char *pat = "^((add|ins|append|prepend|del)[:=]"
+ "|(mod|imod)[:=][^,]*=ro"
+ "|(noplink|ro)$)";
+
+
+ o = strdup(opts);
+ if (!o)
+ AuFin("stdup");
+
+ p = o;
+ i = 1;
+ while ((p = strchr(p, ','))) {
+ i++;
+ *p++ = 0;
+ }
+
+ /* todo: try getsubopt(3)? */
+ err = regcomp(&preg, pat, REG_EXTENDED | REG_NOSUB);
+ if (err)
+ AuFin("regcomp");
+
+ p = o;
+ while (i--) {
+ if (!regexec(&preg, p, 0, NULL, 0)) {
+ err = 1;
+ break;
+ } else
+ p += strlen(p) + 1;
+ }
+ regfree(&preg);
+ free(o);
+
+ return err;
+}
+
+static void do_mount(char *dev, char *mntpnt, int argc, char *argv[],
+ unsigned char flags[])
+{
+ int i;
+ const int ac = argc + 6;
+ char *av[ac], **a;
+
+ /* todo: eliminate the duplicated options */
+ a = av;
+ *a++ = "mount";
+ *a++ = "-i";
+ if (flags[Fake])
+ *a++ = "-f";
+ if (!flags[Bind] || !flags[Update])
+ *a++ = "-n";
+ if (flags[Bind] && flags[Verbose])
+ *a++ = "-v";
+ *a++ = "-t";
+ *a++ = AUFS_NAME;
+
+ for (i = 3; i < argc; i++)
+ if (strcmp(argv[i], "-v") && strcmp(argv[i], "-n"))
+ *a++ = argv[i];
+ *a++ = dev;
+ *a++ = mntpnt;
+ *a++ = NULL;
+
+#ifdef DEBUG
+ for (i = 0; av[i] && i < ac; i++)
+ puts(av[i]);
+ exit(0);
+#endif
+ execvp("mount", av);
+ AuFin("mount");
+}
+
+/* ---------------------------------------------------------------------- */
+
+int main(int argc, char *argv[])
+{
+ int err, c, status;
+ pid_t pid;
+ unsigned char flags[LastOpt];
+ struct mntent ent;
+ char *dev, *mntpnt, *opts, *cwd;
+ DIR *cur;
+
+ if (argc < 3) {
+ errno = EINVAL;
+ AuFin(NULL);
+ }
+
+ memset(flags, 0, sizeof(flags));
+ flags[Update] = 1;
+ opts = NULL;
+
+ /* mount(8) always passes the arguments in this order */
+ dev = argv[1];
+ mntpnt = argv[2];
+ while ((c = getopt(argc - 2, argv + 2, "fnvo:")) != -1) {
+ switch (c) {
+ case 'f':
+ flags[Fake] = 1;
+ break;
+ case 'n':
+ flags[Update] = 0;
+ break;
+ case 'v':
+ flags[Verbose] = 1;
+ break;
+ case 'o':
+ opts = optarg;
+ break;
+ case '?':
+ case ':':
+ errno = EINVAL;
+ AuFin("internal error");
+ }
+ }
+
+ cur = opendir(".");
+ if (!cur)
+ AuFin(".");
+ err = chdir(mntpnt);
+ if (err)
+ AuFin("%s", mntpnt);
+ cwd = getcwd(NULL, 0); /* glibc */
+ if (!cwd)
+ AuFin("getcwd");
+ err = fchdir(dirfd(cur));
+ if (err)
+ AuFin("fchdir");
+ closedir(cur); /* ignore */
+
+ if (opts)
+ test_opts(opts, flags);
+
+ if (!flags[Bind] && flags[Update]) {
+ err = access(MTab, R_OK | W_OK);
+ if (err)
+ AuFin(MTab);
+ }
+
+ if (flags[Remount]) {
+ errno = EINVAL;
+ if (flags[Bind])
+ AuFin("both of remount and bind are specified");
+ flags[AuFlush] = test_flush(opts);
+ if (flags[AuFlush] /* && !flags[Fake] */) {
+ err = au_plink(cwd, AuPlink_FLUSH, 1, 1);
+ if (err)
+ AuFin(NULL);
+ }
+ }
+
+ pid = fork();
+ if (!pid) {
+ /* actual mount operation */
+ do_mount(dev, mntpnt, argc, argv, flags);
+ return 0;
+ } else if (pid < 0)
+ AuFin("fork");
+
+ err = waitpid(pid, &status, 0);
+ if (err < 0)
+ AuFin("child process");
+
+ err = !WIFEXITED(status);
+ if (!err)
+ err = WEXITSTATUS(status);
+
+ if (!err && !flags[Bind]) {
+ if (flags[Update])
+ err = au_update_mtab(cwd, flags[Remount],
+ flags[Verbose]);
+ else if (flags[Verbose]) {
+ /* withoug blocking plink */
+ err = au_proc_getmntent(cwd, &ent);
+ if (!err)
+ au_print_ent(&ent);
+ else
+ AuFin("internal error");
+ }
+ }
+
+ return err;
+}
diff --git a/package/aufs2-util/src/mtab.c b/package/aufs2-util/src/mtab.c
new file mode 100644
index 000000000..713e9e267
--- /dev/null
+++ b/package/aufs2-util/src/mtab.c
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2005-2009 Junjiro Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* cf. fstab.c or the locking for /etc/mtab in util-linux */
+/*
+ * we need to extract a part of util-linux and create a simple and generic
+ * library for locking /etc/mtab.
+ */
+
+/* #include <linux/proc_fs.h> */
+#define PROC_SUPER_MAGIC 0x9fa0
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <mntent.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "au_util.h"
+
+void au_print_ent(struct mntent *ent)
+{
+ printf("%s on %s type %s (%s)\n",
+ ent->mnt_fsname, ent->mnt_dir, ent->mnt_type, ent->mnt_opts);
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void lock_mtab(char *pid_file)
+{
+ int err, i;
+
+ for (i = 0; i < 5; i++) {
+ err = link(pid_file, MTab "~");
+ if (!err)
+ break;
+ sleep(1);
+ }
+ if (err)
+ AuFin(MTab "~");
+}
+
+static void unlock_mtab(void)
+{
+ int err;
+
+ err = rename(MTab "~", MTab);
+ if (err)
+ AuFin(MTab);
+}
+
+static void append_mtab(FILE *fp, FILE *ofp, struct mntent *ent)
+{
+ int err;
+ struct mntent *p;
+
+ while ((p = getmntent(ofp))) {
+ err = addmntent(fp, p);
+ if (err)
+ AuFin("addmntent");
+ }
+
+ err = addmntent(fp, ent);
+ if (err)
+ AuFin("addmntent");
+}
+
+/* todo: there are some cases which options are not changed */
+static void update_mtab(FILE *fp, char *mntpnt, int do_remount, int do_verbose)
+{
+ int err;
+ long pos;
+ FILE *ofp;
+ struct mntent ent, *p;
+
+ /* prohibit updating mount options for this mntpnt */
+ au_plink_maint(mntpnt);
+ err = au_proc_getmntent(mntpnt, &ent);
+ if (err)
+ AuFin("no such mount point");
+
+ ofp = setmntent(MTab, "r");
+ if (!ofp)
+ AuFin(MTab);
+
+ if (do_remount) {
+ /* find the last one */
+ pos = -1;
+ while ((p = getmntent(ofp))) {
+ if (!strcmp(p->mnt_dir, mntpnt))
+ pos = ftell(ofp);
+ }
+ rewind(ofp);
+
+ if (pos > 0) {
+ while ((p = getmntent(ofp))) {
+ if (ftell(ofp) == pos) {
+ /* replace the line */
+ p = &ent;
+ pos = -1;
+ }
+ err = addmntent(fp, p);
+ if (err)
+ AuFin("addmntent");
+ }
+ if (pos > 0)
+ AuFin("internal error");
+ } else
+ append_mtab(fp, ofp, &ent);
+ } else
+ append_mtab(fp, ofp, &ent);
+
+ endmntent(ofp); /* ignore */
+ au_plink_maint(NULL);
+ if (do_verbose)
+ au_print_ent(&ent);
+}
+
+/* ---------------------------------------------------------------------- */
+
+int au_update_mtab(char *mntpnt, int do_remount, int do_verbose)
+{
+ int err, fd, status, e2;
+ pid_t pid;
+ ino_t ino;
+ struct stat st;
+ struct statfs stfs;
+ struct flock flock = {
+ .l_type = F_WRLCK,
+ .l_whence = SEEK_SET,
+ .l_start = 0,
+ .l_len = 0
+ };
+ char pid_file[sizeof(MTab "~.") + 20];
+ FILE *fp;
+
+ err = statfs(MTab, &stfs);
+ if (stfs.f_type == PROC_SUPER_MAGIC)
+ return 0;
+
+ snprintf(pid_file, sizeof(pid_file), MTab "~.%d", getpid());
+ fd = open(pid_file, O_RDWR | O_CREAT | O_EXCL,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ if (fd < 0)
+ AuFin("%s", pid_file);
+ err = fcntl(fd, F_SETLK, &flock);
+ if (err)
+ AuFin("%s", pid_file);
+ fp = fdopen(fd, "r+");
+ if (!fp)
+ AuFin("%s", pid_file);
+
+ pid = fork();
+ if (!pid) {
+ lock_mtab(pid_file);
+ update_mtab(fp, mntpnt, do_remount, do_verbose);
+ unlock_mtab();
+ return 0;
+ } else if (pid < 0)
+ AuFin("fork");
+
+ err = fstat(fd, &st);
+ if (err)
+ perror(pid_file);
+ ino = st.st_ino;
+
+ err = waitpid(pid, &status, 0);
+ if (err < 0) {
+ perror(pid_file);
+ goto out;
+ }
+ err = !WIFEXITED(status);
+ if (!err)
+ err = WEXITSTATUS(status);
+
+ e2 = unlink(pid_file);
+ if (e2 && errno != ENOENT)
+ perror(pid_file);
+ e2 = stat(MTab "~", &st);
+ if (!e2) {
+ if (st.st_ino == ino) {
+ /*
+ * The inode number is same,
+ * it means it is we who made the file.
+ * If someone else removed our file between stat(2) and
+ * unlink(2), it is a breakage of the rule.
+ */
+ e2 = unlink(MTab "~");
+ if (e2)
+ perror(MTab);
+ }
+ } else if (errno != ENOENT)
+ perror(MTab "~");
+ fclose(fp);
+
+ out:
+ return err;
+}
diff --git a/package/aufs2-util/src/plink.c b/package/aufs2-util/src/plink.c
new file mode 100644
index 000000000..6ff16c76a
--- /dev/null
+++ b/package/aufs2-util/src/plink.c
@@ -0,0 +1,356 @@
+/*
+ * Copyright (C) 2005-2009 Junjiro Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define _FILE_OFFSET_BITS 64 /* ftw.h */
+#define _XOPEN_SOURCE 500 /* ftw.h */
+#define _GNU_SOURCE /* ftw.h */
+
+#include <sys/ioctl.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <ftw.h>
+#include <mntent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <linux/aufs_type.h>
+#include "au_util.h"
+
+/* todo: try argz? */
+static struct name_array {
+ char *o;
+ int bytes;
+
+ char *cur;
+ int nname;
+} na;
+
+static struct ino_array {
+ char *o;
+ int bytes;
+
+ union {
+ char *p;
+ ino_t *cur;
+ };
+ int nino;
+} ia;
+
+static int na_append(char *plink_dir, char *name)
+{
+ int l, sz;
+ char *p;
+ const int cur = na.cur - na.o;
+
+ l = strlen(plink_dir) + strlen(name) + 2;
+ sz = na.bytes + l;
+ p = realloc(na.o, sz);
+ if (!p)
+ AuFin("realloc");
+
+ na.o = p;
+ na.bytes = sz;
+ na.cur = p + cur;
+ na.cur += sprintf(na.cur, "%s/%s", plink_dir, name) + 1;
+ na.nname++;
+
+ return 0;
+}
+
+static int ia_append(ino_t ino)
+{
+ int sz;
+ char *p;
+ const int cur = ia.p - ia.o;
+
+ sz = na.bytes + sizeof(ino_t);
+ p = realloc(ia.o, sz);
+ if (!p)
+ AuFin("realloc");
+
+ ia.o = p;
+ ia.bytes = sz;
+ ia.p = p + cur;
+ *ia.cur++ = ino;
+ ia.nino++;
+
+ return 0;
+}
+
+static int build_array(char *plink_dir)
+{
+ int err;
+ DIR *dp;
+ struct dirent *de;
+ char *p;
+ ino_t ino;
+
+ err = access(plink_dir, F_OK);
+ if (err)
+ return 0;
+
+ err = 0;
+ dp = opendir(plink_dir);
+ if (!dp)
+ AuFin("%s", plink_dir);
+ while ((de = readdir(dp))) {
+ if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
+ continue;
+#if 0
+ if (de->d_type == DT_DIR) {
+ errno = EISDIR;
+ AuFin(de->d_name);
+ }
+#endif
+
+ err = na_append(plink_dir, de->d_name);
+ if (err)
+ break;
+
+ p = strchr(de->d_name, '.');
+ if (!p) {
+ errno = EINVAL;
+ AuFin("internal error, %s", de->d_name);
+ }
+ *p = 0;
+ errno = 0;
+ ino = strtoull(de->d_name, NULL, 0);
+ if (ino == /*ULLONG_MAX*/-1 && errno == ERANGE)
+ AuFin("internal error, %s", de->d_name);
+ err = ia_append(ino);
+ if (err)
+ break;
+ }
+ closedir(dp);
+
+ return err;
+}
+
+static int ia_test(ino_t ino)
+{
+ int i;
+ ino_t *p;
+
+ /* todo: hash table */
+ ia.p = ia.o;
+ p = ia.cur;
+ for (i = 0; i < ia.nino; i++)
+ if (*p++ == ino)
+ return 1;
+ return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int ftw_list(const char *fname, const struct stat *st, int flags,
+ struct FTW *ftw)
+{
+ if (!strcmp(fname + ftw->base, AUFS_WH_PLINKDIR))
+ return FTW_SKIP_SUBTREE;
+ if (flags == FTW_D || flags == FTW_DNR)
+ return FTW_CONTINUE;
+
+ if (ia_test(st->st_ino))
+ puts(fname);
+
+ return FTW_CONTINUE;
+}
+
+static int ftw_cpup(const char *fname, const struct stat *st, int flags,
+ struct FTW *ftw)
+{
+ int err;
+
+ if (!strcmp(fname + ftw->base, AUFS_WH_PLINKDIR))
+ return FTW_SKIP_SUBTREE;
+ if (flags == FTW_D || flags == FTW_DNR)
+ return FTW_CONTINUE;
+
+ /*
+ * do nothing but update something harmless in order to make it copyup
+ */
+ if (ia_test(st->st_ino)) {
+ Dpri("%s\n", fname);
+ if (!S_ISLNK(st->st_mode))
+ err = chown(fname, -1, -1);
+ else
+ err = lchown(fname, -1, -1);
+ if (err)
+ AuFin("%s", fname);
+ }
+
+ return FTW_CONTINUE;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static DIR *dp;
+void au_plink_maint(char *path)
+{
+ int err;
+
+ if (path) {
+ if (dp) {
+ errno = EINVAL;
+ AuFin("dp is not NULL");
+ }
+ dp = opendir(path);
+ if (!dp)
+ AuFin("%s", path);
+
+ err = ioctl(dirfd(dp), AUFS_CTL_PLINK_MAINT);
+#ifndef DEBUG
+ if (err)
+ AuFin("AUFS_CTL_PLINK_MAINT");
+#endif
+ } else {
+ err = closedir(dp);
+ if (err)
+ AuFin("closedir");
+ dp = NULL;
+ }
+}
+
+void au_clean_plink(void)
+{
+ int err;
+
+ err = ioctl(dirfd(dp), AUFS_CTL_PLINK_CLEAN);
+#ifndef DEBUG
+ if (err)
+ AuFin("AUFS_CTL_PLINK_CLEAN");
+#endif
+}
+
+static int do_plink(char *cwd, int cmd, int nbr, char *br[])
+{
+ int err, i, l;
+ struct rlimit rlim;
+ __nftw_func_t func;
+ char *p;
+
+ err = 0;
+ switch (cmd) {
+ case AuPlink_FLUSH:
+ /*FALLTHROUGH*/
+ case AuPlink_CPUP:
+ func = ftw_cpup;
+ break;
+ case AuPlink_LIST:
+ func = ftw_list;
+ break;
+ default:
+ errno = EINVAL;
+ AuFin(NULL);
+ func = NULL; /* never reach here */
+ }
+
+ for (i = 0; i < nbr; i++) {
+ //puts(br[i]);
+ p = strchr(br[i], '=');
+ if (strcmp(p + 1, AUFS_BRPERM_RW)
+ && strcmp(p + 1, AUFS_BRPERM_RWNLWH))
+ continue;
+
+ *p = 0;
+ l = strlen(br[i]);
+ p = malloc(l + sizeof(AUFS_WH_PLINKDIR) + 2);
+ if (!p)
+ AuFin("malloc");
+ sprintf(p, "%s/%s", br[i], AUFS_WH_PLINKDIR);
+ //puts(p);
+ err = build_array(p);
+ if (err)
+ AuFin("build_array");
+ free(p);
+ }
+ if (!ia.nino)
+ goto out;
+
+ if (cmd == AuPlink_LIST) {
+ ia.p = ia.o;
+ for (i = 0; i < ia.nino; i++)
+ printf("%llu ", (unsigned long long)*ia.cur++);
+ putchar('\n');
+ }
+
+ err = getrlimit(RLIMIT_NOFILE, &rlim);
+ if (err)
+ AuFin("getrlimit");
+ nftw(cwd, func, rlim.rlim_cur - 10,
+ FTW_PHYS | FTW_MOUNT | FTW_ACTIONRETVAL);
+ /* ignore */
+
+ if (cmd == AuPlink_FLUSH) {
+ au_clean_plink();
+
+ na.cur = na.o;
+ for (i = 0; i < na.nname; i++) {
+ Dpri("%s\n", na.cur);
+ err = unlink(na.cur);
+ if (err)
+ AuFin("%s", na.cur);
+ na.cur += strlen(na.cur) + 1;
+ }
+ }
+
+ out:
+ free(ia.o);
+ free(na.o);
+ return err;
+}
+
+int au_plink(char cwd[], int cmd, int begin_maint, int end_maint)
+{
+ int err, nbr;
+ struct mntent ent;
+ char **br;
+
+ if (begin_maint)
+ au_plink_maint(cwd);
+
+ err = au_proc_getmntent(cwd, &ent);
+ if (err)
+ AuFin("no such mount point");
+
+ if (hasmntopt(&ent, "noplink"))
+ goto out; /* success */
+
+#ifdef DEBUG
+ //char a[] = "a,b,br:/tmp/br0=rw:/br1=ro";
+ char a[] = "a,b,si=1,c";
+ ent.mnt_opts = a;
+#endif
+ err = au_br(&br, &nbr, &ent);
+ //printf("nbr %d\n", nbr);
+ if (err)
+ AuFin(NULL);
+
+ err = do_plink(cwd, cmd, nbr, br);
+ if (err)
+ AuFin(NULL);
+
+ out:
+ if (end_maint)
+ au_plink_maint(NULL);
+ return err;
+}
diff --git a/package/aufs2-util/src/proc_mnt.c b/package/aufs2-util/src/proc_mnt.c
new file mode 100644
index 000000000..5230aa259
--- /dev/null
+++ b/package/aufs2-util/src/proc_mnt.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2005-2009 Junjiro Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <mntent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "au_util.h"
+
+#define ProcMounts "/proc/self/mounts"
+
+static void copy_ent(struct mntent *dst, struct mntent *src)
+{
+ free(dst->mnt_opts);
+ free(dst->mnt_type);
+ free(dst->mnt_dir);
+ free(dst->mnt_fsname);
+
+ dst->mnt_dir = NULL;
+ dst->mnt_type = NULL;
+ dst->mnt_opts = NULL;
+
+ dst->mnt_fsname = strdup(src->mnt_fsname);
+ if (dst->mnt_fsname)
+ dst->mnt_dir = strdup(src->mnt_dir);
+ if (dst->mnt_dir)
+ dst->mnt_type = strdup(src->mnt_type);
+ if (dst->mnt_type)
+ dst->mnt_opts = strdup(src->mnt_opts);
+ if (dst->mnt_opts) {
+ dst->mnt_freq = src->mnt_freq;
+ dst->mnt_passno = src->mnt_passno;
+ } else
+ AuFin("strdup");
+
+}
+
+int au_proc_getmntent(char *mntpnt, struct mntent *rent)
+{
+ int found;
+ struct mntent *p;
+ FILE *fp;
+
+ fp = setmntent(ProcMounts, "r");
+ if (!fp)
+ AuFin(ProcMounts);
+
+ /* find the last one */
+ memset(rent, 0, sizeof(*rent));
+ found = 0;
+ while ((p = getmntent(fp)))
+ if (!strcmp(p->mnt_dir, mntpnt)) {
+ Dpri("%s, %s, %s, %s, %d, %d\n",
+ p->mnt_fsname, p->mnt_dir, p->mnt_type,
+ p->mnt_opts, p->mnt_freq, p->mnt_passno);
+ copy_ent(rent, p);
+ found = 1;
+ }
+ endmntent(fp);
+
+ if (!found) {
+ errno = EINVAL;
+ AuFin("%s", mntpnt);
+ }
+
+ return 0;
+}
diff --git a/package/aufs2-util/src/rdu.c b/package/aufs2-util/src/rdu.c
new file mode 100644
index 000000000..ac958f084
--- /dev/null
+++ b/package/aufs2-util/src/rdu.c
@@ -0,0 +1,749 @@
+/*
+ * Copyright (C) 2009 Junjiro Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define _ATFILE_SOURCE
+#define _GNU_SOURCE
+#define _REENTRANT
+
+#include <linux/aufs_type.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/vfs.h> /* or <sys/statfs.h> */
+#include <assert.h>
+#include <dirent.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <search.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "compat.h"
+
+/* ---------------------------------------------------------------------- */
+
+struct rdu {
+#ifdef AuRDU_REENTRANT
+ pthread_rwlock_t lock;
+#else
+ struct dirent de;
+#endif
+
+ int fd;
+
+ unsigned long npos, idx;
+ struct au_rdu_ent **pos;
+
+ unsigned long nent, sz;
+ struct au_rdu_ent *ent;
+
+ int shwh;
+ struct au_rdu_ent *real, *wh;
+};
+
+static struct rdu **rdu;
+#define RDU_STEP 8
+static int rdu_cur, rdu_lim = RDU_STEP;
+
+/* ---------------------------------------------------------------------- */
+
+/* #define RduLocalTest */
+#ifdef RduLocalTest
+static int rdu_test_data(struct rdu *p, int err)
+{
+ struct au_rdu_ent *e = p->ent;
+ static int i;
+
+ if (!i++) {
+ err = 3;
+ e->ino = e->type = e->nlen = 1;
+ strcpy(e->name, ".");
+ e += au_rdu_len(e->nlen);
+ e->ino = e->type = e->nlen = 2;
+ strcpy(e->name, "..");
+ e += au_rdu_len(e->nlen);
+ e->ino = e->type = e->nlen = 3;
+ strcpy(e->name, "foo");
+ } else
+ err = 0;
+
+ return err;
+}
+#else
+static int rdu_test_data(struct rdu *p, int err)
+{
+ return err;
+}
+#endif
+
+/* #define RduDebug */
+#ifdef RduDebug
+#define DPri(fmt, args...) fprintf(stderr, "%s:%d: " fmt, \
+ __func__, __LINE__, ##args)
+#else
+#define DPri(fmt, args...) do {} while (0)
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+#ifdef AuRDU_REENTRANT
+static void rdu_rwlock_init(struct rdu *p)
+{
+ pthread_rwlock_init(&p->lock);
+}
+
+static void rdu_read_lock(struct rdu *p)
+{
+ pthread_rwlock_rdlock(&p->lock);
+}
+
+static void rdu_write_lock(struct rdu *p)
+{
+ pthread_rwlock_wrlock(&p->lock);
+}
+
+static void rdu_unlock(struct rdu *p)
+{
+ pthread_rwlock_unlock(&p->lock);
+}
+
+static pthread_mutex_t rdu_lib_mtx = PTHREAD_MUTEX_INITIALIZER;
+#define rdu_lib_lock() pthread_mutex_lock(&rdu_lib_mtx)
+#define rdu_lib_unlock() pthread_mutex_unlock(&rdu_lib_mtx)
+#define rdu_lib_must_lock() assert(pthread_mutex_trylock(&rdu_lib_mtx))
+#else
+static void rdu_rwlock_init(struct rdu *p)
+{
+ /* empty */
+}
+
+static void rdu_read_lock(struct rdu *p)
+{
+ /* empty */
+}
+
+static void rdu_write_lock(struct rdu *p)
+{
+ /* empty */
+}
+
+static void rdu_unlock(struct rdu *p)
+{
+ /* empty */
+}
+
+#define rdu_lib_lock() do {} while(0)
+#define rdu_lib_unlock() do {} while(0)
+#define rdu_lib_must_lock() do {} while(0)
+#endif
+
+/*
+ * initialize this library, particularly global variables.
+ */
+static int rdu_lib_init(void)
+{
+ int err;
+
+ err = 0;
+ if (rdu)
+ goto out;
+
+ rdu_lib_lock();
+ if (!rdu) {
+ rdu = calloc(rdu_lim, sizeof(*rdu));
+ err = !rdu;
+ }
+ rdu_lib_unlock();
+
+ out:
+ return err;
+}
+
+static int rdu_append(struct rdu *p)
+{
+ int err, i;
+ void *t;
+
+ rdu_lib_must_lock();
+
+ err = 0;
+ if (rdu_cur < rdu_lim - 1)
+ rdu[rdu_cur++] = p;
+ else {
+ t = realloc(rdu, rdu_lim + RDU_STEP * sizeof(*rdu));
+ if (t) {
+ rdu = t;
+ rdu_lim += RDU_STEP;
+ rdu[rdu_cur++] = p;
+ for (i = 0; i < RDU_STEP - 1; i++)
+ rdu[rdu_cur + i] = NULL;
+ } else
+ err = -1;
+ }
+
+ return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static struct rdu *rdu_new(int fd)
+{
+ struct rdu *p;
+ int err;
+
+ p = malloc(sizeof(*p));
+ if (p) {
+ rdu_rwlock_init(p);
+ p->fd = fd;
+ p->sz = BUFSIZ;
+ p->ent = malloc(BUFSIZ);
+ if (p->ent) {
+ err = rdu_append(p);
+ if (!err)
+ goto out; /* success */
+ }
+ }
+ free(p);
+ p = NULL;
+
+ out:
+ return p;
+}
+
+static struct rdu *rdu_buf_lock(int fd)
+{
+ struct rdu *p;
+ int i;
+
+ assert(rdu);
+ assert(fd >= 0);
+
+ p = NULL;
+ rdu_lib_lock();
+ for (i = 0; i < rdu_cur; i++)
+ if (rdu[i] && rdu[i]->fd == fd) {
+ p = rdu[i];
+ goto out;
+ }
+
+ for (i = 0; i < rdu_cur; i++)
+ if (rdu[i] && rdu[i]->fd == -1) {
+ p = rdu[i];
+ p->fd = fd;
+ goto out;
+ }
+ if (!p)
+ p = rdu_new(fd);
+
+ out:
+ if (p)
+ rdu_write_lock(p);
+ rdu_lib_unlock();
+
+ return p;
+}
+
+static void rdu_free(int fd)
+{
+ struct rdu *p;
+
+ p = rdu_buf_lock(fd);
+ if (p) {
+ free(p->ent);
+ free(p->pos);
+ p->fd = -1;
+ p->ent = NULL;
+ p->pos = NULL;
+ rdu_unlock(p);
+ }
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int rdu_do_store(int dirfd, struct au_rdu_ent *ent,
+ struct au_rdu_ent **pos, struct rdu *p)
+{
+ int err;
+ unsigned char c;
+ struct stat st;
+
+ c = ent->name[ent->nlen];
+ ent->name[ent->nlen] = 0;
+ DPri("%s\n", ent->name);
+ err = fstatat(dirfd, ent->name, &st, AT_SYMLINK_NOFOLLOW);
+ ent->name[ent->nlen] = c;
+ if (!err) {
+ ent->ino = st.st_ino;
+ pos[p->idx++] = ent;
+ } else {
+ DPri("err %d\n", err);
+ if (errno == ENOENT)
+ err = 0;
+ }
+
+ return err;
+}
+
+struct rdu_thread_arg {
+ int pipefd;
+ struct rdu *p;
+};
+
+static void *rdu_thread(void *_arg)
+{
+ int err, pipefd, dirfd;
+ ssize_t ssz;
+ struct rdu_thread_arg *arg = _arg;
+ struct au_rdu_ent *ent, **pos;
+ struct rdu *p;
+
+ pipefd = arg->pipefd;
+ p = arg->p;
+ dirfd = p->fd;
+ pos = p->pos;
+ while (1) {
+ DPri("read\n");
+ ssz = read(pipefd, &ent, sizeof(ent));
+ DPri("ssz %zd\n", ssz);
+ if (ssz != sizeof(ent) || !ent) {
+ //perror("read");
+ break;
+ }
+
+ //DPri("%p\n", ent);
+ err = rdu_do_store(dirfd, ent, pos, p);
+ }
+
+ DPri("here\n");
+ return NULL;
+}
+
+static int rdu_store(struct rdu *p, struct au_rdu_ent *ent, int pipefd)
+{
+#ifdef RduLocalTest
+ if (ent)
+ return rdu_do_store(p->fd, ent, p->pos, p);
+ return 0;
+#else
+ ssize_t ssz;
+
+ //DPri("%p\n", ent);
+ ssz = write(pipefd, &ent, sizeof(ent));
+ DPri("ssz %zd\n", ssz);
+ //sleep(1);
+ return ssz != sizeof(ent);
+#endif
+}
+
+/* ---------------------------------------------------------------------- */
+/* the heart of this library */
+
+static void rdu_tfree(void *node)
+{
+ /* empty */
+}
+
+static int rdu_ent_compar(const void *_a, const void *_b)
+{
+ int ret;
+ const struct au_rdu_ent *a = _a, *b = _b;
+
+ ret = (int)a->nlen - b->nlen;
+ if (!ret)
+ ret = memcmp(a->name, b->name, a->nlen);
+ return ret;
+}
+
+static int rdu_ent_compar_wh(const void *_a, const void *_b)
+{
+ int ret;
+ const struct au_rdu_ent *real = _a, *wh = _b;
+
+ if (real->nlen >= AUFS_WH_PFX_LEN
+ && !memcmp(real->name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) {
+ wh = _a;
+ real = _b;
+ }
+
+ ret = (int)wh->nlen - AUFS_WH_PFX_LEN - real->nlen;
+ if (!ret)
+ ret = memcmp(wh->name + AUFS_WH_PFX_LEN, real->name,
+ real->nlen);
+ return ret;
+}
+
+/* tsearch(3) may not be thread-safe */
+static int rdu_ent_append(struct rdu *p, struct au_rdu_ent *ent, int pipefd)
+{
+ int err;
+ struct au_rdu_ent *e;
+
+ err = 0;
+ e = tfind(ent, (void *)&p->wh, rdu_ent_compar_wh);
+ if (e)
+ goto out;
+
+ e = tsearch(ent, (void *)&p->real, rdu_ent_compar);
+ if (e)
+ err = rdu_store(p, ent, pipefd);
+ else
+ err = -1;
+
+ out:
+ return err;
+}
+
+static int rdu_ent_append_wh(struct rdu *p, struct au_rdu_ent *ent, int pipefd)
+{
+ int err;
+ struct au_rdu_ent *e;
+
+ err = 0;
+ e = tfind(ent, (void *)&p->wh, rdu_ent_compar);
+ if (e)
+ goto out;
+
+ e = tsearch(ent, (void *)&p->wh, rdu_ent_compar);
+ if (e) {
+ if (p->shwh)
+ err = rdu_store(p, ent, pipefd);
+ } else
+ err = -1;
+
+ out:
+ return err;
+}
+
+static int rdu_merge(struct rdu *p)
+{
+ int err;
+ unsigned long ul;
+ pthread_t th;
+ int fds[2];
+ struct rdu_thread_arg arg;
+ struct au_rdu_ent *ent;
+ void *t;
+
+ err = -1;
+ p->pos = malloc(sizeof(*p->pos) * p->npos);
+ if (!p->pos)
+ goto out;
+
+ /* pipe(2) may not be scheduled well in linux-2.6.23 and earlier */
+ err = pipe(fds);
+ if (err)
+ goto out_free;
+
+ arg.pipefd = fds[0];
+ arg.p = p;
+#ifndef RduLocalTest
+ err = pthread_create(&th, NULL, rdu_thread, &arg);
+#endif
+ if (err)
+ goto out_close;
+
+ p->real = NULL;
+ p->wh = NULL;
+ ent = p->ent;
+ for (ul = 0; !err && ul < p->npos; ul++) {
+ if (ent->nlen <= AUFS_WH_PFX_LEN
+ || strncmp(ent->name, AUFS_WH_PFX, AUFS_WH_PFX_LEN))
+ err = rdu_ent_append(p, ent, fds[1]);
+ else
+ err = rdu_ent_append_wh(p, ent, fds[1]);
+ ent += au_rdu_len(ent->nlen);
+ }
+ rdu_store(p, /*ent*/NULL, fds[1]); /* terminate the thread */
+ tdestroy(p->real, rdu_tfree);
+ tdestroy(p->wh, rdu_tfree);
+
+#ifndef RduLocalTest
+ pthread_join(th, NULL);
+#endif
+ p->npos = p->idx;
+ t = realloc(p->pos, sizeof(*p->pos) * p->npos);
+ if (t)
+ p->pos = t;
+ /* t == NULL is not an error */
+
+ out_close:
+ close(fds[1]);
+ close(fds[0]);
+ if (!err)
+ goto out; /* success */
+ out_free:
+ free(p->pos);
+ p->pos = NULL;
+ out:
+ return err;
+}
+
+static int rdu_init(struct rdu *p)
+{
+ int err;
+ struct aufs_rdu param;
+ char *t;
+
+ memset(&param, 0, sizeof(param));
+ param.ent = p->ent;
+ param.sz = p->sz;
+ t = getenv("AUFS_RDU_BLK");
+ if (t)
+ param.blk = strtoul(t + sizeof("AUFS_RDU_BLK"), NULL, 0);
+
+ do {
+ err = ioctl(p->fd, AUFS_CTL_RDU, &param);
+ err = rdu_test_data(p, err);
+ if (err > 0) {
+ p->npos += err;
+ if (!param.full)
+ continue;
+
+ assert(param.blk);
+ t = realloc(p->ent, p->sz + param.blk);
+ if (t) {
+ param.sz = param.blk;
+ param.ent = (void *)(t + p->sz);
+ p->ent = (void *)t;
+ p->sz += param.blk;
+ } else
+ err = -1;
+ }
+ } while (err > 0);
+ p->shwh = param.shwh;
+ if (!err)
+ err = rdu_merge(p);
+
+ if (err) {
+ free(p->ent);
+ p->ent = NULL;
+ }
+
+ return err;
+}
+
+static int rdu_pos(struct dirent *de, struct rdu *p, long pos)
+{
+ int err;
+ struct au_rdu_ent *ent;
+
+ err = -1;
+ if (pos <= p->npos) {
+ ent = p->pos[pos];
+ de->d_ino = ent->ino;
+ de->d_off = pos;
+ de->d_reclen = sizeof(*ent) + ent->nlen;
+ de->d_type = ent->type;
+ memcpy(de->d_name, ent->name, ent->nlen);
+ de->d_name[ent->nlen] = 0;
+ err = 0;
+ }
+ return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static struct dirent *(*real_readdir)(DIR *dir);
+static int (*real_readdir_r)(DIR *dir, struct dirent *de, struct dirent **rde);
+static int (*real_closedir)(DIR *dir);
+
+static int rdu_dl(void **real, char *sym)
+{
+ char *p;
+
+ if (*real)
+ return 0;
+
+ dlerror(); /* clear */
+ *real = dlsym(RTLD_NEXT, sym);
+ p = dlerror();
+ if (p)
+ fprintf(stderr, "%s\n", p);
+ return !!p;
+}
+
+#define RduDlFunc(sym) \
+static int rdu_dl_##sym(void) \
+{ \
+ return rdu_dl((void *)&real_##sym, #sym); \
+}
+
+RduDlFunc(readdir);
+RduDlFunc(closedir);
+
+#ifdef AuRDU_REENTRANT
+RduDlFunc(readdir_r);
+#else
+#define rdu_dl_readdir_r() 1
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+static int rdu_readdir(DIR *dir, struct dirent *de, struct dirent **rde)
+{
+ int err, fd;
+ struct rdu *p;
+ long pos;
+ struct statfs stfs;
+
+ if (rde)
+ *rde = NULL;
+
+ errno = EBADF;
+ fd = dirfd(dir);
+ err = fd;
+ if (fd < 0)
+ goto out;
+
+ err = fstatfs(fd, &stfs);
+ if (err)
+ goto out;
+
+ if (
+#ifdef RduLocalTest
+ 1 ||
+#endif
+ stfs.f_type == AUFS_SUPER_MAGIC) {
+ err = rdu_lib_init();
+ if (err)
+ goto out;
+
+ p = rdu_buf_lock(fd);
+ if (!p)
+ goto out;
+
+ pos = telldir(dir);
+ if (!pos || !p->npos) {
+ err = rdu_init(p);
+ rdu_unlock(p);
+ }
+ if (err)
+ goto out;
+
+ rdu_read_lock(p);
+ if (!de)
+ de = &p->de;
+ err = rdu_pos(de, p, pos);
+ rdu_unlock(p);
+ if (!err) {
+ *rde = de;
+ seekdir(dir, pos + 1);
+ }
+ } else if (!de) {
+ if (!rdu_dl_readdir()) {
+ err = 0;
+ *rde = real_readdir(dir);
+ if (!*rde)
+ err = -1;
+ }
+ } else {
+ if (!rdu_dl_readdir_r())
+ err = real_readdir_r(dir, de, rde);
+ }
+ out:
+ return err;
+}
+
+struct dirent *readdir(DIR *dir)
+{
+ struct dirent *de;
+ int err;
+
+ err = rdu_readdir(dir, NULL, &de);
+ DPri("err %d\n", err);
+ return de;
+}
+
+#ifdef AuRDU_REENTRANT
+int readdir_r(DIR *dirp, struct dirent *de, struct dirent **rde)
+{
+ return rdu_readdir(dir, de, rde);
+}
+#endif
+
+int closedir(DIR *dir)
+{
+ int err, fd;
+ struct statfs stfs;
+
+ errno = EBADF;
+ fd = dirfd(dir);
+ if (fd < 0)
+ goto out;
+ err = fstatfs(fd, &stfs);
+ if (err)
+ goto out;
+
+ if (stfs.f_type == AUFS_SUPER_MAGIC)
+ rdu_free(fd);
+ if (!rdu_dl_closedir())
+ err = real_closedir(dir);
+
+ out:
+ return err;
+}
+
+#if 0
+extern DIR *opendir (__const char *__name) __nonnull ((1));
+extern int closedir (DIR *__dirp) __nonnull ((1));
+extern struct dirent *__REDIRECT (readdir, (DIR *__dirp), readdir64)
+ __nonnull ((1));
+extern struct dirent64 *readdir64 (DIR *__dirp) __nonnull ((1));
+extern int readdir_r (DIR *__restrict __dirp,
+ struct dirent *__restrict __entry,
+ struct dirent **__restrict __result)
+ __nonnull ((1, 2, 3));
+extern int readdir64_r (DIR *__restrict __dirp,
+ struct dirent64 *__restrict __entry,
+ struct dirent64 **__restrict __result)
+ __nonnull ((1, 2, 3));
+extern void rewinddir (DIR *__dirp) __THROW __nonnull ((1));
+extern void seekdir (DIR *__dirp, long int __pos) __THROW __nonnull ((1));
+extern long int telldir (DIR *__dirp) __THROW __nonnull ((1));
+extern int dirfd (DIR *__dirp) __THROW __nonnull ((1));
+extern int scandir (__const char *__restrict __dir,
+ struct dirent ***__restrict __namelist,
+ int (*__selector) (__const struct dirent *),
+ int (*__cmp) (__const void *, __const void *))
+ __nonnull ((1, 2));
+extern int scandir64 (__const char *__restrict __dir,
+ struct dirent64 ***__restrict __namelist,
+ int (*__selector) (__const struct dirent64 *),
+ int (*__cmp) (__const void *, __const void *))
+ __nonnull ((1, 2));
+extern int alphasort (__const void *__e1, __const void *__e2)
+ __THROW __attribute_pure__ __nonnull ((1, 2));
+extern int alphasort64 (__const void *__e1, __const void *__e2)
+ __THROW __attribute_pure__ __nonnull ((1, 2));
+extern int versionsort (__const void *__e1, __const void *__e2)
+ __THROW __attribute_pure__ __nonnull ((1, 2));
+extern int versionsort64 (__const void *__e1, __const void *__e2)
+ __THROW __attribute_pure__ __nonnull ((1, 2));
+extern __ssize_t getdirentries (int __fd, char *__restrict __buf,
+ size_t __nbytes,
+ __off_t *__restrict __basep)
+ __THROW __nonnull ((2, 4));
+extern __ssize_t getdirentries64 (int __fd, char *__restrict __buf,
+ size_t __nbytes,
+ __off64_t *__restrict __basep)
+ __THROW __nonnull ((2, 4));
+#endif
diff --git a/package/aufs2-util/src/umount.aufs b/package/aufs2-util/src/umount.aufs
new file mode 100755
index 000000000..395689236
--- /dev/null
+++ b/package/aufs2-util/src/umount.aufs
@@ -0,0 +1,31 @@
+#!/bin/sh -
+
+# Copyright (C) 2005-2009 Junjiro Okajima
+#
+# This program, aufs is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+#
+# The main purpose of this script is calling auplink.
+#
+
+PATH=/usr/bin:/usr/sbin:/bin:/sbin
+export PATH
+
+set -e
+#set -x; echo $0 $@
+dev="$1"
+shift
+auplink "$dev" flush
+exec umount -i $@ "$dev"