diff options
Diffstat (limited to 'package/aufs2-util/src')
-rw-r--r-- | package/aufs2-util/src/COPYING | 340 | ||||
-rw-r--r-- | package/aufs2-util/src/Makefile | 103 | ||||
-rw-r--r-- | package/aufs2-util/src/README | 46 | ||||
-rw-r--r-- | package/aufs2-util/src/au_util.h | 67 | ||||
-rwxr-xr-x | package/aufs2-util/src/aubrsync | 304 | ||||
-rwxr-xr-x | package/aufs2-util/src/auchk | 130 | ||||
-rw-r--r-- | package/aufs2-util/src/aufs.in.5 | 1684 | ||||
-rw-r--r-- | package/aufs2-util/src/aufs.shlib | 83 | ||||
-rw-r--r-- | package/aufs2-util/src/auplink.c | 64 | ||||
-rw-r--r-- | package/aufs2-util/src/br.c | 172 | ||||
-rw-r--r-- | package/aufs2-util/src/c2sh.c | 42 | ||||
-rw-r--r-- | package/aufs2-util/src/c2tmac.c | 44 | ||||
-rw-r--r-- | package/aufs2-util/src/compat.h | 34 | ||||
-rw-r--r-- | package/aufs2-util/src/mount.aufs.c | 255 | ||||
-rw-r--r-- | package/aufs2-util/src/mtab.c | 216 | ||||
-rw-r--r-- | package/aufs2-util/src/plink.c | 356 | ||||
-rw-r--r-- | package/aufs2-util/src/proc_mnt.c | 85 | ||||
-rw-r--r-- | package/aufs2-util/src/rdu.c | 749 | ||||
-rwxr-xr-x | package/aufs2-util/src/umount.aufs | 31 |
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(¶m, 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, ¶m); + 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" |