bring in fusermount
This commit is contained in:
parent
fbb636390f
commit
901ba842cd
@ -1,6 +1,6 @@
|
||||
EXTRA_DIST = autogen.sh COPYING INSTALL README AUTHORS THANKS NEWS glusterfs.spec
|
||||
|
||||
SUBDIRS = argp-standalone libglusterfs $(LIBGLUSTERFSCLIENT_SUBDIR) xlators scheduler transport auth glusterfsd $(GF_BOOSTER_SUBDIR) doc extras
|
||||
SUBDIRS = argp-standalone libglusterfs $(LIBGLUSTERFSCLIENT_SUBDIR) xlators scheduler transport auth glusterfsd $(GF_BOOSTER_SUBDIR) $(FUSERMOUNT_SUBDIR) doc extras
|
||||
|
||||
CLEANFILES =
|
||||
|
||||
|
24
configure.ac
24
configure.ac
@ -124,6 +124,8 @@ AC_CONFIG_FILES([Makefile
|
||||
extras/init.d/glusterfsd-Redhat
|
||||
extras/init.d/glusterfsd-SuSE
|
||||
extras/benchmarking/Makefile
|
||||
contrib/Makefile
|
||||
contrib/fuse-util/Makefile
|
||||
glusterfs.spec])
|
||||
|
||||
AC_CANONICAL_HOST
|
||||
@ -216,6 +218,24 @@ AC_SUBST(FUSE_CLIENT_SUBDIR)
|
||||
# end FUSE section
|
||||
|
||||
|
||||
# FUSERMOUNT section
|
||||
AC_ARG_ENABLE([fusermount],
|
||||
AC_HELP_STRING([--enable-fusermount],
|
||||
[Build fusermount]),
|
||||
[], [enable_fusermount=no])
|
||||
|
||||
BUILD_FUSERMOUNT="no"
|
||||
|
||||
if test "x$enable_fusermount" != "xno"; then
|
||||
FUSERMOUNT_SUBDIR="contrib"
|
||||
BUILD_FUSERMOUNT="yes"
|
||||
AC_DEFINE(GF_FUSERMOUNT, 1, [Use our own fusermount])
|
||||
fi
|
||||
|
||||
AC_SUBST(FUSERMOUNT_SUBDIR)
|
||||
#end FUSERMOUNT section
|
||||
|
||||
|
||||
# EPOLL section
|
||||
AC_ARG_ENABLE([epoll],
|
||||
AC_HELP_STRING([--disable-epoll],
|
||||
@ -454,6 +474,9 @@ AC_SUBST(GF_LDADD)
|
||||
AC_SUBST(GF_FUSE_LDADD)
|
||||
AC_SUBST(GF_BOOSTER_SUBDIR)
|
||||
|
||||
CONTRIBDIR='$(top_srcdir)/contrib'
|
||||
AC_SUBST(CONTRIBDIR)
|
||||
|
||||
AM_CONDITIONAL([GF_DARWIN_HOST_OS], test "${GF_HOST_OS}" = "GF_DARWIN_HOST_OS")
|
||||
|
||||
AC_OUTPUT
|
||||
@ -467,4 +490,5 @@ echo "epoll IO multiplex : $BUILD_EPOLL"
|
||||
echo "Berkeley-DB : $BUILD_BDB"
|
||||
echo "libglusterfsclient : $BUILD_LIBGLUSTERFSCLIENT"
|
||||
echo "argp-standalone : $BUILD_ARGP_STANDALONE"
|
||||
echo "fusermount : $BUILD_FUSERMOUNT"
|
||||
echo
|
||||
|
3
contrib/Makefile.am
Normal file
3
contrib/Makefile.am
Normal file
@ -0,0 +1,3 @@
|
||||
SUBDIRS = fuse-util
|
||||
|
||||
CLEANFILES =
|
@ -7,28 +7,46 @@
|
||||
See the file COPYING.LIB.
|
||||
*/
|
||||
|
||||
#ifndef _CONFIG_H
|
||||
#define _CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stddef.h>
|
||||
#include <limits.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <dirent.h>
|
||||
#include <mntent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
#ifdef FUSE_UTIL
|
||||
#define MALLOC(size) malloc (size)
|
||||
#define FREE(ptr) free (ptr)
|
||||
#define GFFUSE_LOGERR(...) fprintf (stderr, ## __VA_ARGS__)
|
||||
#else /* FUSE_UTIL */
|
||||
#include "glusterfs.h"
|
||||
#include "logging.h"
|
||||
#include "common-utils.h"
|
||||
|
||||
#ifdef GF_FUSERMOUNT
|
||||
#define FUSERMOUNT_PROG FUSERMOUNT_DIR "/fusermount-glusterfs"
|
||||
#else
|
||||
#define FUSERMOUNT_PROG "fusermount"
|
||||
#endif
|
||||
#define FUSE_COMMFD_ENV "_FUSE_COMMFD"
|
||||
|
||||
#define GFFUSE_LOGERR(...) \
|
||||
gf_log ("glusterfs-fuse", GF_LOG_ERROR, ## __VA_ARGS__)
|
||||
#endif /* !FUSE_UTIL */
|
||||
|
||||
/*
|
||||
* Functions below, until following note, were taken from libfuse
|
||||
@ -74,7 +92,10 @@ mtab_needs_update (const char *mnt)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
#ifndef FUSE_UTIL
|
||||
static
|
||||
#endif
|
||||
int
|
||||
fuse_mnt_add_mount (const char *progname, const char *fsname,
|
||||
const char *mnt, const char *type, const char *opts)
|
||||
{
|
||||
@ -141,7 +162,10 @@ fuse_mnt_add_mount (const char *progname, const char *fsname,
|
||||
return res;
|
||||
}
|
||||
|
||||
static char
|
||||
#ifndef FUSE_UTIL
|
||||
static
|
||||
#endif
|
||||
char
|
||||
*fuse_mnt_resolve_path (const char *progname, const char *orig)
|
||||
{
|
||||
char buf[PATH_MAX];
|
||||
@ -208,6 +232,7 @@ static char
|
||||
return dst;
|
||||
}
|
||||
|
||||
#ifndef FUSE_UTIL
|
||||
/* return value:
|
||||
* >= 0 => fd
|
||||
* -1 => error
|
||||
@ -305,8 +330,12 @@ fuse_mount_fusermount (const char *mountpoint, const char *opts)
|
||||
|
||||
return rv;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
#ifndef FUSE_UTIL
|
||||
static
|
||||
#endif
|
||||
int
|
||||
fuse_mnt_umount (const char *progname, const char *mnt, int lazy)
|
||||
{
|
||||
int res;
|
||||
@ -357,6 +386,62 @@ fuse_mnt_umount (const char *progname, const char *mnt, int lazy)
|
||||
return res;
|
||||
}
|
||||
|
||||
#ifdef FUSE_UTIL
|
||||
int
|
||||
fuse_mnt_check_empty (const char *progname, const char *mnt,
|
||||
mode_t rootmode, off_t rootsize)
|
||||
{
|
||||
int isempty = 1;
|
||||
|
||||
if (S_ISDIR (rootmode)) {
|
||||
struct dirent *ent;
|
||||
DIR *dp = opendir (mnt);
|
||||
if (dp == NULL) {
|
||||
fprintf (stderr,
|
||||
"%s: failed to open mountpoint for reading: %s\n",
|
||||
progname, strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
while ((ent = readdir (dp)) != NULL) {
|
||||
if (strcmp (ent->d_name, ".") != 0 &&
|
||||
strcmp (ent->d_name, "..") != 0) {
|
||||
isempty = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
closedir (dp);
|
||||
} else if (rootsize)
|
||||
isempty = 0;
|
||||
|
||||
if (!isempty) {
|
||||
fprintf (stderr, "%s: mountpoint is not empty\n", progname);
|
||||
fprintf (stderr, "%s: if you are sure this is safe, "
|
||||
"use the 'nonempty' mount option\n", progname);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
fuse_mnt_check_fuseblk (void)
|
||||
{
|
||||
char buf[256];
|
||||
FILE *f = fopen ("/proc/filesystems", "r");
|
||||
if (!f)
|
||||
return 1;
|
||||
|
||||
while (fgets (buf, sizeof (buf), f))
|
||||
if (strstr (buf, "fuseblk\n")) {
|
||||
fclose (f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fclose (f);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef FUSE_UTIL
|
||||
void
|
||||
gf_fuse_unmount (const char *mountpoint, int fd)
|
||||
{
|
||||
@ -404,11 +489,13 @@ gf_fuse_unmount (const char *mountpoint, int fd)
|
||||
}
|
||||
waitpid (pid, NULL, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Functions below are loosely modelled after similar functions of libfuse
|
||||
*/
|
||||
|
||||
#ifndef FUSE_UTIL
|
||||
static int
|
||||
fuse_mount_sys (const char *mountpoint, char *fsname, char *mnt_param)
|
||||
{
|
||||
@ -526,3 +613,4 @@ gf_fuse_mount (const char *mountpoint, char *fsname, char *mnt_param)
|
||||
|
||||
return fd;
|
||||
}
|
||||
#endif
|
||||
|
340
contrib/fuse-util/COPYING
Normal file
340
contrib/fuse-util/COPYING
Normal file
@ -0,0 +1,340 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Library 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Library General
|
||||
Public License instead of this License.
|
12
contrib/fuse-util/Makefile.am
Normal file
12
contrib/fuse-util/Makefile.am
Normal file
@ -0,0 +1,12 @@
|
||||
bin_PROGRAMS = fusermount-glusterfs
|
||||
|
||||
fusermount_glusterfs_SOURCES = fusermount.c $(CONTRIBDIR)/fuse-lib/mount.c
|
||||
noinst_HEADERS = mount_util.h
|
||||
|
||||
AM_CFLAGS = -Wall -D_FILE_OFFSET_BITS=64 -DFUSE_UTIL $(GF_CFLAGS)
|
||||
|
||||
install-exec-hook:
|
||||
chown root $(DESTDIR)$(bindir)/fusermount-glusterfs
|
||||
chmod u+s $(DESTDIR)$(bindir)/fusermount-glusterfs
|
||||
|
||||
CLEANFILES =
|
965
contrib/fuse-util/fusermount.c
Normal file
965
contrib/fuse-util/fusermount.c
Normal file
@ -0,0 +1,965 @@
|
||||
/*
|
||||
FUSE: Filesystem in Userspace
|
||||
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
This program can be distributed under the terms of the GNU GPL.
|
||||
See the file COPYING.
|
||||
*/
|
||||
/* This program does the mounting and unmounting of FUSE filesystems */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "mount_util.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <pwd.h>
|
||||
#include <mntent.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/fsuid.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#define FUSE_COMMFD_ENV "_FUSE_COMMFD"
|
||||
|
||||
#define FUSE_DEV_OLD "/proc/fs/fuse/dev"
|
||||
#define FUSE_DEV_NEW "/dev/fuse"
|
||||
#define FUSE_VERSION_FILE_OLD "/proc/fs/fuse/version"
|
||||
#define FUSE_CONF "/etc/fuse.conf"
|
||||
|
||||
#ifndef MS_DIRSYNC
|
||||
#define MS_DIRSYNC 128
|
||||
#endif
|
||||
|
||||
static const char *progname;
|
||||
|
||||
static int user_allow_other = 0;
|
||||
static int mount_max = 1000;
|
||||
|
||||
static const char *get_user_name(void)
|
||||
{
|
||||
struct passwd *pw = getpwuid(getuid());
|
||||
if (pw != NULL && pw->pw_name != NULL)
|
||||
return pw->pw_name;
|
||||
else {
|
||||
fprintf(stderr, "%s: could not determine username\n", progname);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static uid_t oldfsuid;
|
||||
static gid_t oldfsgid;
|
||||
|
||||
static void drop_privs(void)
|
||||
{
|
||||
if (getuid() != 0) {
|
||||
oldfsuid = setfsuid(getuid());
|
||||
oldfsgid = setfsgid(getgid());
|
||||
}
|
||||
}
|
||||
|
||||
static void restore_privs(void)
|
||||
{
|
||||
if (getuid() != 0) {
|
||||
setfsuid(oldfsuid);
|
||||
setfsgid(oldfsgid);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGNORE_MTAB
|
||||
static int add_mount(const char *source, const char *mnt, const char *type,
|
||||
const char *opts)
|
||||
{
|
||||
return fuse_mnt_add_mount(progname, source, mnt, type, opts);
|
||||
}
|
||||
|
||||
static int unmount_fuse(const char *mnt, int quiet, int lazy)
|
||||
{
|
||||
if (getuid() != 0) {
|
||||
struct mntent *entp;
|
||||
FILE *fp;
|
||||
const char *user = NULL;
|
||||
char uidstr[32];
|
||||
unsigned uidlen = 0;
|
||||
int found;
|
||||
const char *mtab = _PATH_MOUNTED;
|
||||
|
||||
user = get_user_name();
|
||||
if (user == NULL)
|
||||
return -1;
|
||||
|
||||
fp = setmntent(mtab, "r");
|
||||
if (fp == NULL) {
|
||||
fprintf(stderr,
|
||||
"%s: failed to open %s: %s\n", progname, mtab,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
uidlen = sprintf(uidstr, "%u", getuid());
|
||||
|
||||
found = 0;
|
||||
while ((entp = getmntent(fp)) != NULL) {
|
||||
if (!found && strcmp(entp->mnt_dir, mnt) == 0 &&
|
||||
(strcmp(entp->mnt_type, "fuse") == 0 ||
|
||||
strcmp(entp->mnt_type, "fuseblk") == 0 ||
|
||||
strncmp(entp->mnt_type, "fuse.", 5) == 0 ||
|
||||
strncmp(entp->mnt_type, "fuseblk.", 8) == 0)) {
|
||||
char *p = strstr(entp->mnt_opts, "user=");
|
||||
if (p &&
|
||||
(p == entp->mnt_opts || *(p-1) == ',') &&
|
||||
strcmp(p + 5, user) == 0) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
/* /etc/mtab is a link pointing to
|
||||
/proc/mounts: */
|
||||
else if ((p =
|
||||
strstr(entp->mnt_opts, "user_id=")) &&
|
||||
(p == entp->mnt_opts ||
|
||||
*(p-1) == ',') &&
|
||||
strncmp(p + 8, uidstr, uidlen) == 0 &&
|
||||
(*(p+8+uidlen) == ',' ||
|
||||
*(p+8+uidlen) == '\0')) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
endmntent(fp);
|
||||
|
||||
if (!found) {
|
||||
if (!quiet)
|
||||
fprintf(stderr,
|
||||
"%s: entry for %s not found in %s\n",
|
||||
progname, mnt, mtab);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return fuse_mnt_umount(progname, mnt, lazy);
|
||||
}
|
||||
|
||||
static int count_fuse_fs(void)
|
||||
{
|
||||
struct mntent *entp;
|
||||
int count = 0;
|
||||
const char *mtab = _PATH_MOUNTED;
|
||||
FILE *fp = setmntent(mtab, "r");
|
||||
if (fp == NULL) {
|
||||
fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
while ((entp = getmntent(fp)) != NULL) {
|
||||
if (strcmp(entp->mnt_type, "fuse") == 0 ||
|
||||
strncmp(entp->mnt_type, "fuse.", 5) == 0)
|
||||
count ++;
|
||||
}
|
||||
endmntent(fp);
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
#else /* IGNORE_MTAB */
|
||||
static int count_fuse_fs()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_mount(const char *source, const char *mnt, const char *type,
|
||||
const char *opts)
|
||||
{
|
||||
(void) source;
|
||||
(void) mnt;
|
||||
(void) type;
|
||||
(void) opts;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unmount_fuse(const char *mnt, int quiet, int lazy)
|
||||
{
|
||||
return fuse_mnt_umount(progname, mnt, lazy);
|
||||
}
|
||||
#endif /* IGNORE_MTAB */
|
||||
|
||||
static void strip_line(char *line)
|
||||
{
|
||||
char *s = strchr(line, '#');
|
||||
if (s != NULL)
|
||||
s[0] = '\0';
|
||||
for (s = line + strlen(line) - 1;
|
||||
s >= line && isspace((unsigned char) *s); s--);
|
||||
s[1] = '\0';
|
||||
for (s = line; isspace((unsigned char) *s); s++);
|
||||
if (s != line)
|
||||
memmove(line, s, strlen(s)+1);
|
||||
}
|
||||
|
||||
static void parse_line(char *line, int linenum)
|
||||
{
|
||||
int tmp;
|
||||
if (strcmp(line, "user_allow_other") == 0)
|
||||
user_allow_other = 1;
|
||||
else if (sscanf(line, "mount_max = %i", &tmp) == 1)
|
||||
mount_max = tmp;
|
||||
else if(line[0])
|
||||
fprintf(stderr,
|
||||
"%s: unknown parameter in %s at line %i: '%s'\n",
|
||||
progname, FUSE_CONF, linenum, line);
|
||||
}
|
||||
|
||||
static void read_conf(void)
|
||||
{
|
||||
FILE *fp = fopen(FUSE_CONF, "r");
|
||||
if (fp != NULL) {
|
||||
int linenum = 1;
|
||||
char line[256];
|
||||
int isnewline = 1;
|
||||
while (fgets(line, sizeof(line), fp) != NULL) {
|
||||
if (isnewline) {
|
||||
if (line[strlen(line)-1] == '\n') {
|
||||
strip_line(line);
|
||||
parse_line(line, linenum);
|
||||
} else {
|
||||
isnewline = 0;
|
||||
}
|
||||
} else if(line[strlen(line)-1] == '\n') {
|
||||
fprintf(stderr, "%s: reading %s: line %i too long\n", progname, FUSE_CONF, linenum);
|
||||
|
||||
isnewline = 1;
|
||||
}
|
||||
if (isnewline)
|
||||
linenum ++;
|
||||
}
|
||||
if (!isnewline) {
|
||||
fprintf(stderr, "%s: reading %s: missing newline at end of file\n", progname, FUSE_CONF);
|
||||
|
||||
}
|
||||
fclose(fp);
|
||||
} else if (errno != ENOENT) {
|
||||
fprintf(stderr, "%s: failed to open %s: %s\n",
|
||||
progname, FUSE_CONF, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
static int begins_with(const char *s, const char *beg)
|
||||
{
|
||||
if (strncmp(s, beg, strlen(beg)) == 0)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct mount_flags {
|
||||
const char *opt;
|
||||
unsigned long flag;
|
||||
int on;
|
||||
int safe;
|
||||
};
|
||||
|
||||
static struct mount_flags mount_flags[] = {
|
||||
{"rw", MS_RDONLY, 0, 1},
|
||||
{"ro", MS_RDONLY, 1, 1},
|
||||
{"suid", MS_NOSUID, 0, 0},
|
||||
{"nosuid", MS_NOSUID, 1, 1},
|
||||
{"dev", MS_NODEV, 0, 0},
|
||||
{"nodev", MS_NODEV, 1, 1},
|
||||
{"exec", MS_NOEXEC, 0, 1},
|
||||
{"noexec", MS_NOEXEC, 1, 1},
|
||||
{"async", MS_SYNCHRONOUS, 0, 1},
|
||||
{"sync", MS_SYNCHRONOUS, 1, 1},
|
||||
{"atime", MS_NOATIME, 0, 1},
|
||||
{"noatime", MS_NOATIME, 1, 1},
|
||||
{"dirsync", MS_DIRSYNC, 1, 1},
|
||||
{NULL, 0, 0, 0}
|
||||
};
|
||||
|
||||
static int find_mount_flag(const char *s, unsigned len, int *on, int *flag)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; mount_flags[i].opt != NULL; i++) {
|
||||
const char *opt = mount_flags[i].opt;
|
||||
if (strlen(opt) == len && strncmp(opt, s, len) == 0) {
|
||||
*on = mount_flags[i].on;
|
||||
*flag = mount_flags[i].flag;
|
||||
if (!mount_flags[i].safe && getuid() != 0) {
|
||||
*flag = 0;
|
||||
fprintf(stderr,
|
||||
"%s: unsafe option %s ignored\n",
|
||||
progname, opt);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_option(char **optsp, const char *opt, unsigned expand)
|
||||
{
|
||||
char *newopts;
|
||||
if (*optsp == NULL)
|
||||
newopts = strdup(opt);
|
||||
else {
|
||||
unsigned oldsize = strlen(*optsp);
|
||||
unsigned newsize = oldsize + 1 + strlen(opt) + expand + 1;
|
||||
newopts = (char *) realloc(*optsp, newsize);
|
||||
if (newopts)
|
||||
sprintf(newopts + oldsize, ",%s", opt);
|
||||
}
|
||||
if (newopts == NULL) {
|
||||
fprintf(stderr, "%s: failed to allocate memory\n", progname);
|
||||
return -1;
|
||||
}
|
||||
*optsp = newopts;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_mnt_opts(int flags, char *opts, char **mnt_optsp)
|
||||
{
|
||||
int i;
|
||||
int l;
|
||||
|
||||
if (!(flags & MS_RDONLY) && add_option(mnt_optsp, "rw", 0) == -1)
|
||||
return -1;
|
||||
|
||||
for (i = 0; mount_flags[i].opt != NULL; i++) {
|
||||
if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
|
||||
add_option(mnt_optsp, mount_flags[i].opt, 0) == -1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (add_option(mnt_optsp, opts, 0) == -1)
|
||||
return -1;
|
||||
/* remove comma from end of opts*/
|
||||
l = strlen(*mnt_optsp);
|
||||
if ((*mnt_optsp)[l-1] == ',')
|
||||
(*mnt_optsp)[l-1] = '\0';
|
||||
if (getuid() != 0) {
|
||||
const char *user = get_user_name();
|
||||
if (user == NULL)
|
||||
return -1;
|
||||
|
||||
if (add_option(mnt_optsp, "user=", strlen(user)) == -1)
|
||||
return -1;
|
||||
strcat(*mnt_optsp, user);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opt_eq(const char *s, unsigned len, const char *opt)
|
||||
{
|
||||
if(strlen(opt) == len && strncmp(s, opt, len) == 0)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_string_opt(const char *s, unsigned len, const char *opt,
|
||||
char **val)
|
||||
{
|
||||
unsigned opt_len = strlen(opt);
|
||||
|
||||
if (*val)
|
||||
free(*val);
|
||||
*val = (char *) malloc(len - opt_len + 1);
|
||||
if (!*val) {
|
||||
fprintf(stderr, "%s: failed to allocate memory\n", progname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(*val, s + opt_len, len - opt_len);
|
||||
(*val)[len - opt_len] = '\0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int do_mount(const char *mnt, char **typep, mode_t rootmode,
|
||||
int fd, const char *opts, const char *dev, char **sourcep,
|
||||
char **mnt_optsp, off_t rootsize)
|
||||
{
|
||||
int res;
|
||||
int flags = MS_NOSUID | MS_NODEV;
|
||||
char *optbuf;
|
||||
char *mnt_opts = NULL;
|
||||
const char *s;
|
||||
char *d;
|
||||
char *fsname = NULL;
|
||||
char *subtype = NULL;
|
||||
char *source = NULL;
|
||||
char *type = NULL;
|
||||
int check_empty = 1;
|
||||
int blkdev = 0;
|
||||
|
||||
optbuf = (char *) malloc(strlen(opts) + 128);
|
||||
if (!optbuf) {
|
||||
fprintf(stderr, "%s: failed to allocate memory\n", progname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (s = opts, d = optbuf; *s;) {
|
||||
unsigned len;
|
||||
const char *fsname_str = "fsname=";
|
||||
const char *subtype_str = "subtype=";
|
||||
for (len = 0; s[len] && s[len] != ','; len++);
|
||||
if (begins_with(s, fsname_str)) {
|
||||
if (!get_string_opt(s, len, fsname_str, &fsname))
|
||||
goto err;
|
||||
} else if (begins_with(s, subtype_str)) {
|
||||
if (!get_string_opt(s, len, subtype_str, &subtype))
|
||||
goto err;
|
||||
} else if (opt_eq(s, len, "blkdev")) {
|
||||
if (getuid() != 0) {
|
||||
fprintf(stderr,
|
||||
"%s: option blkdev is privileged\n",
|
||||
progname);
|
||||
goto err;
|
||||
}
|
||||
blkdev = 1;
|
||||
} else if (opt_eq(s, len, "nonempty")) {
|
||||
check_empty = 0;
|
||||
} else if (!begins_with(s, "fd=") &&
|
||||
!begins_with(s, "rootmode=") &&
|
||||
!begins_with(s, "user_id=") &&
|
||||
!begins_with(s, "group_id=")) {
|
||||
int on;
|
||||
int flag;
|
||||
int skip_option = 0;
|
||||
if (opt_eq(s, len, "large_read")) {
|
||||
struct utsname utsname;
|
||||
unsigned kmaj, kmin;
|
||||
res = uname(&utsname);
|
||||
if (res == 0 &&
|
||||
sscanf(utsname.release, "%u.%u",
|
||||
&kmaj, &kmin) == 2 &&
|
||||
(kmaj > 2 || (kmaj == 2 && kmin > 4))) {
|
||||
fprintf(stderr, "%s: note: 'large_read' mount option is deprecated for %i.%i kernels\n", progname, kmaj, kmin);
|
||||
skip_option = 1;
|
||||
}
|
||||
}
|
||||
if (getuid() != 0 && !user_allow_other &&
|
||||
(opt_eq(s, len, "allow_other") ||
|
||||
opt_eq(s, len, "allow_root"))) {
|
||||
fprintf(stderr, "%s: option %.*s only allowed if 'user_allow_other' is set in /etc/fuse.conf\n", progname, len, s);
|
||||
goto err;
|
||||
}
|
||||
if (!skip_option) {
|
||||
if (find_mount_flag(s, len, &on, &flag)) {
|
||||
if (on)
|
||||
flags |= flag;
|
||||
else
|
||||
flags &= ~flag;
|
||||
} else {
|
||||
memcpy(d, s, len);
|
||||
d += len;
|
||||
*d++ = ',';
|
||||
}
|
||||
}
|
||||
}
|
||||
s += len;
|
||||
if (*s)
|
||||
s++;
|
||||
}
|
||||
*d = '\0';
|
||||
res = get_mnt_opts(flags, optbuf, &mnt_opts);
|
||||
if (res == -1)
|
||||
goto err;
|
||||
|
||||
sprintf(d, "fd=%i,rootmode=%o,user_id=%i,group_id=%i",
|
||||
fd, rootmode, getuid(), getgid());
|
||||
|
||||
if (check_empty &&
|
||||
fuse_mnt_check_empty(progname, mnt, rootmode, rootsize) == -1)
|
||||
goto err;
|
||||
|
||||
source = malloc((fsname ? strlen(fsname) : 0) +
|
||||
(subtype ? strlen(subtype) : 0) + strlen(dev) + 32);
|
||||
|
||||
type = malloc((subtype ? strlen(subtype) : 0) + 32);
|
||||
if (!type || !source) {
|
||||
fprintf(stderr, "%s: failed to allocate memory\n", progname);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (subtype)
|
||||
sprintf(type, "%s.%s", blkdev ? "fuseblk" : "fuse", subtype);
|
||||
else
|
||||
strcpy(type, blkdev ? "fuseblk" : "fuse");
|
||||
|
||||
if (fsname)
|
||||
strcpy(source, fsname);
|
||||
else
|
||||
strcpy(source, subtype ? subtype : dev);
|
||||
|
||||
res = mount(source, mnt, type, flags, optbuf);
|
||||
if (res == -1 && errno == ENODEV && subtype) {
|
||||
/* Probably missing subtype support */
|
||||
strcpy(type, blkdev ? "fuseblk" : "fuse");
|
||||
if (fsname) {
|
||||
if (!blkdev)
|
||||
sprintf(source, "%s#%s", subtype, fsname);
|
||||
} else {
|
||||
strcpy(source, type);
|
||||
}
|
||||
|
||||
res = mount(source, mnt, type, flags, optbuf);
|
||||
}
|
||||
if (res == -1 && errno == EINVAL) {
|
||||
/* It could be an old version not supporting group_id */
|
||||
sprintf(d, "fd=%i,rootmode=%o,user_id=%i",
|
||||
fd, rootmode, getuid());
|
||||
res = mount(source, mnt, type, flags, optbuf);
|
||||
}
|
||||
if (res == -1) {
|
||||
int errno_save = errno;
|
||||
if (blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk())
|
||||
fprintf(stderr, "%s: 'fuseblk' support missing\n",
|
||||
progname);
|
||||
else
|
||||
fprintf(stderr, "%s: mount failed: %s\n", progname,
|
||||
strerror(errno_save));
|
||||
goto err;
|
||||
} else {
|
||||
*sourcep = source;
|
||||
*typep = type;
|
||||
*mnt_optsp = mnt_opts;
|
||||
}
|
||||
free(fsname);
|
||||
free(optbuf);
|
||||
|
||||
return res;
|
||||
|
||||
err:
|
||||
free(fsname);
|
||||
free(subtype);
|
||||
free(source);
|
||||
free(type);
|
||||
free(mnt_opts);
|
||||
free(optbuf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int check_version(const char *dev)
|
||||
{
|
||||
int res;
|
||||
int majorver;
|
||||
int minorver;
|
||||
const char *version_file;
|
||||
FILE *vf;
|
||||
|
||||
if (strcmp(dev, FUSE_DEV_OLD) != 0)
|
||||
return 0;
|
||||
|
||||
version_file = FUSE_VERSION_FILE_OLD;
|
||||
vf = fopen(version_file, "r");
|
||||
if (vf == NULL) {
|
||||
fprintf(stderr, "%s: kernel interface too old\n", progname);
|
||||
return -1;
|
||||
}
|
||||
res = fscanf(vf, "%i.%i", &majorver, &minorver);
|
||||
fclose(vf);
|
||||
if (res != 2) {
|
||||
fprintf(stderr, "%s: error reading %s\n", progname,
|
||||
version_file);
|
||||
return -1;
|
||||
}
|
||||
if (majorver < 3) {
|
||||
fprintf(stderr, "%s: kernel interface too old\n", progname);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_perm(const char **mntp, struct stat *stbuf, int *currdir_fd,
|
||||
int *mountpoint_fd)
|
||||
{
|
||||
int res;
|
||||
const char *mnt = *mntp;
|
||||
const char *origmnt = mnt;
|
||||
|
||||
res = lstat(mnt, stbuf);
|
||||
if (res == -1) {
|
||||
fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
|
||||
progname, mnt, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* No permission checking is done for root */
|
||||
if (getuid() == 0)
|
||||
return 0;
|
||||
|
||||
if (S_ISDIR(stbuf->st_mode)) {
|
||||
*currdir_fd = open(".", O_RDONLY);
|
||||
if (*currdir_fd == -1) {
|
||||
fprintf(stderr,
|
||||
"%s: failed to open current directory: %s\n",
|
||||
progname, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
res = chdir(mnt);
|
||||
if (res == -1) {
|
||||
fprintf(stderr,
|
||||
"%s: failed to chdir to mountpoint: %s\n",
|
||||
progname, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
mnt = *mntp = ".";
|
||||
res = lstat(mnt, stbuf);
|
||||
if (res == -1) {
|
||||
fprintf(stderr,
|
||||
"%s: failed to access mountpoint %s: %s\n",
|
||||
progname, origmnt, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((stbuf->st_mode & S_ISVTX) && stbuf->st_uid != getuid()) {
|
||||
fprintf(stderr, "%s: mountpoint %s not owned by user\n",
|
||||
progname, origmnt);
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = access(mnt, W_OK);
|
||||
if (res == -1) {
|
||||
fprintf(stderr, "%s: user has no write access to mountpoint %s\n",
|
||||
progname, origmnt);
|
||||
return -1;
|
||||
}
|
||||
} else if (S_ISREG(stbuf->st_mode)) {
|
||||
static char procfile[256];
|
||||
*mountpoint_fd = open(mnt, O_WRONLY);
|
||||
if (*mountpoint_fd == -1) {
|
||||
fprintf(stderr, "%s: failed to open %s: %s\n",
|
||||
progname, mnt, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
res = fstat(*mountpoint_fd, stbuf);
|
||||
if (res == -1) {
|
||||
fprintf(stderr,
|
||||
"%s: failed to access mountpoint %s: %s\n",
|
||||
progname, mnt, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (!S_ISREG(stbuf->st_mode)) {
|
||||
fprintf(stderr,
|
||||
"%s: mountpoint %s is no longer a regular file\n",
|
||||
progname, mnt);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sprintf(procfile, "/proc/self/fd/%i", *mountpoint_fd);
|
||||
*mntp = procfile;
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"%s: mountpoint %s is not a directory or a regular file\n",
|
||||
progname, mnt);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int try_open(const char *dev, char **devp, int silent)
|
||||
{
|
||||
int fd = open(dev, O_RDWR);
|
||||
if (fd != -1) {
|
||||
*devp = strdup(dev);
|
||||
if (*devp == NULL) {
|
||||
fprintf(stderr, "%s: failed to allocate memory\n",
|
||||
progname);
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
} else if (errno == ENODEV ||
|
||||
errno == ENOENT)/* check for ENOENT too, for the udev case */
|
||||
return -2;
|
||||
else if (!silent) {
|
||||
fprintf(stderr, "%s: failed to open %s: %s\n", progname, dev,
|
||||
strerror(errno));
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int try_open_fuse_device(char **devp)
|
||||
{
|
||||
int fd;
|
||||
int err;
|
||||
|
||||
drop_privs();
|
||||
fd = try_open(FUSE_DEV_NEW, devp, 0);
|
||||
restore_privs();
|
||||
if (fd >= 0)
|
||||
return fd;
|
||||
|
||||
err = fd;
|
||||
fd = try_open(FUSE_DEV_OLD, devp, 1);
|
||||
if (fd >= 0)
|
||||
return fd;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int open_fuse_device(char **devp)
|
||||
{
|
||||
int fd = try_open_fuse_device(devp);
|
||||
if (fd >= -1)
|
||||
return fd;
|
||||
|
||||
fprintf(stderr,
|
||||
"%s: fuse device not found, try 'modprobe fuse' first\n",
|
||||
progname);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int mount_fuse(const char *mnt, const char *opts)
|
||||
{
|
||||
int res;
|
||||
int fd;
|
||||
char *dev;
|
||||
struct stat stbuf;
|
||||
char *type = NULL;
|
||||
char *source = NULL;
|
||||
char *mnt_opts = NULL;
|
||||
const char *real_mnt = mnt;
|
||||
int currdir_fd = -1;
|
||||
int mountpoint_fd = -1;
|
||||
|
||||
fd = open_fuse_device(&dev);
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
|
||||
drop_privs();
|
||||
read_conf();
|
||||
|
||||
if (getuid() != 0 && mount_max != -1) {
|
||||
int mount_count = count_fuse_fs();
|
||||
if (mount_count >= mount_max) {
|
||||
fprintf(stderr, "%s: too many FUSE filesystems mounted; mount_max=N can be set in /etc/fuse.conf\n", progname);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
res = check_version(dev);
|
||||
if (res != -1) {
|
||||
res = check_perm(&real_mnt, &stbuf, &currdir_fd,
|
||||
&mountpoint_fd);
|
||||
restore_privs();
|
||||
if (res != -1)
|
||||
res = do_mount(real_mnt, &type, stbuf.st_mode & S_IFMT,
|
||||
fd, opts, dev, &source, &mnt_opts,
|
||||
stbuf.st_size);
|
||||
} else
|
||||
restore_privs();
|
||||
|
||||
if (currdir_fd != -1) {
|
||||
fchdir(currdir_fd);
|
||||
close(currdir_fd);
|
||||
}
|
||||
if (mountpoint_fd != -1)
|
||||
close(mountpoint_fd);
|
||||
|
||||
if (res == -1) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (geteuid() == 0) {
|
||||
res = add_mount(source, mnt, type, mnt_opts);
|
||||
if (res == -1) {
|
||||
umount2(mnt, 2); /* lazy umount */
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
free(source);
|
||||
free(type);
|
||||
free(mnt_opts);
|
||||
free(dev);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int send_fd(int sock_fd, int fd)
|
||||
{
|
||||
int retval;
|
||||
struct msghdr msg;
|
||||
struct cmsghdr *p_cmsg;
|
||||
struct iovec vec;
|
||||
size_t cmsgbuf[CMSG_SPACE(sizeof(fd)) / sizeof(size_t)];
|
||||
int *p_fds;
|
||||
char sendchar = 0;
|
||||
|
||||
msg.msg_control = cmsgbuf;
|
||||
msg.msg_controllen = sizeof(cmsgbuf);
|
||||
p_cmsg = CMSG_FIRSTHDR(&msg);
|
||||
p_cmsg->cmsg_level = SOL_SOCKET;
|
||||
p_cmsg->cmsg_type = SCM_RIGHTS;
|
||||
p_cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
|
||||
p_fds = (int *) CMSG_DATA(p_cmsg);
|
||||
*p_fds = fd;
|
||||
msg.msg_controllen = p_cmsg->cmsg_len;
|
||||
msg.msg_name = NULL;
|
||||
msg.msg_namelen = 0;
|
||||
msg.msg_iov = &vec;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_flags = 0;
|
||||
/* "To pass file descriptors or credentials you need to send/read at
|
||||
* least one byte" (man 7 unix) */
|
||||
vec.iov_base = &sendchar;
|
||||
vec.iov_len = sizeof(sendchar);
|
||||
while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR);
|
||||
if (retval != 1) {
|
||||
perror("sending file descriptor");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"%s: [options] mountpoint\n"
|
||||
"Options:\n"
|
||||
" -h print help\n"
|
||||
" -V print version\n"
|
||||
" -o opt[,opt...] mount options\n"
|
||||
" -u unmount\n"
|
||||
" -q quiet\n"
|
||||
" -z lazy unmount\n",
|
||||
progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void show_version(void)
|
||||
{
|
||||
printf("fusermount version: %s\n", PACKAGE_VERSION);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int ch;
|
||||
int fd;
|
||||
int res;
|
||||
char *origmnt;
|
||||
char *mnt;
|
||||
static int unmount = 0;
|
||||
static int lazy = 0;
|
||||
static int quiet = 0;
|
||||
char *commfd;
|
||||
int cfd;
|
||||
const char *opts = "";
|
||||
|
||||
static const struct option long_opts[] = {
|
||||
{"unmount", no_argument, NULL, 'u'},
|
||||
{"lazy", no_argument, NULL, 'z'},
|
||||
{"quiet", no_argument, NULL, 'q'},
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{"version", no_argument, NULL, 'V'},
|
||||
{0, 0, 0, 0}};
|
||||
|
||||
progname = strdup(argv[0]);
|
||||
if (progname == NULL) {
|
||||
fprintf(stderr, "%s: failed to allocate memory\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while ((ch = getopt_long(argc, argv, "hVo:uzq", long_opts,
|
||||
NULL)) != -1) {
|
||||
switch (ch) {
|
||||
case 'h':
|
||||
usage();
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
show_version();
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
opts = optarg;
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
unmount = 1;
|
||||
break;
|
||||
|
||||
case 'z':
|
||||
lazy = 1;
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
quiet = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (lazy && !unmount) {
|
||||
fprintf(stderr, "%s: -z can only be used with -u\n", progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (optind >= argc) {
|
||||
fprintf(stderr, "%s: missing mountpoint argument\n", progname);
|
||||
exit(1);
|
||||
} else if (argc > optind + 1) {
|
||||
fprintf(stderr, "%s: extra arguments after the mountpoint\n",
|
||||
progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
origmnt = argv[optind];
|
||||
|
||||
drop_privs();
|
||||
mnt = fuse_mnt_resolve_path(progname, origmnt);
|
||||
restore_privs();
|
||||
if (mnt == NULL)
|
||||
exit(1);
|
||||
|
||||
umask(033);
|
||||
if (unmount) {
|
||||
if (geteuid() == 0)
|
||||
res = unmount_fuse(mnt, quiet, lazy);
|
||||
else {
|
||||
res = umount2(mnt, lazy ? 2 : 0);
|
||||
if (res == -1 && !quiet)
|
||||
fprintf(stderr,
|
||||
"%s: failed to unmount %s: %s\n",
|
||||
progname, mnt, strerror(errno));
|
||||
}
|
||||
if (res == -1)
|
||||
exit(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
commfd = getenv(FUSE_COMMFD_ENV);
|
||||
if (commfd == NULL) {
|
||||
fprintf(stderr, "%s: old style mounting not supported\n",
|
||||
progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fd = mount_fuse(mnt, opts);
|
||||
if (fd == -1)
|
||||
exit(1);
|
||||
|
||||
cfd = atoi(commfd);
|
||||
res = send_fd(cfd, fd);
|
||||
if (res == -1)
|
||||
exit(1);
|
||||
|
||||
return 0;
|
||||
}
|
17
contrib/fuse-util/mount_util.h
Normal file
17
contrib/fuse-util/mount_util.h
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
FUSE: Filesystem in Userspace
|
||||
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
This program can be distributed under the terms of the GNU LGPLv2.
|
||||
See the file COPYING.LIB.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
int fuse_mnt_add_mount(const char *progname, const char *fsname,
|
||||
const char *mnt, const char *type, const char *opts);
|
||||
int fuse_mnt_umount(const char *progname, const char *mnt, int lazy);
|
||||
char *fuse_mnt_resolve_path(const char *progname, const char *orig);
|
||||
int fuse_mnt_check_empty(const char *progname, const char *mnt,
|
||||
mode_t rootmode, off_t rootsize);
|
||||
int fuse_mnt_check_fuseblk(void);
|
@ -1,6 +1,3 @@
|
||||
|
||||
CONTRIBDIR = $(top_srcdir)/contrib
|
||||
|
||||
noinst_HEADERS = $(CONTRIBDIR)/fuse-include/fuse_kernel.h
|
||||
|
||||
xlator_LTLIBRARIES = fuse.la
|
||||
@ -11,7 +8,7 @@ fuse_la_LDFLAGS = -module -avoidversion -shared -nostartfiles
|
||||
|
||||
AM_CFLAGS = -fPIC -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -D$(GF_HOST_OS) -Wall \
|
||||
-I$(top_srcdir)/libglusterfs/src -I$(CONTRIBDIR)/fuse-include \
|
||||
$(GF_CFLAGS) -DFUSE_USE_VERSION=26
|
||||
$(GF_CFLAGS) -DFUSERMOUNT_DIR=\"$(bindir)\"
|
||||
|
||||
|
||||
CLEANFILES =
|
||||
|
Loading…
x
Reference in New Issue
Block a user