diff options
| author | Csaba Henk <csaba@gluster.com> | 2009-08-11 18:26:11 -0700 | 
|---|---|---|
| committer | Csaba Henk <csaba@gluster.com> | 2009-08-12 06:26:31 -0700 | 
| commit | 901ba842cd6c42ff24e0539a1b8231b3e802e1ce (patch) | |
| tree | f7dfe8eccefff0836a06c810fbfb69b3a31be4c8 /contrib | |
| parent | fbb636390fe51dc6aa52ec7523a36b183434a28c (diff) | |
bring in fusermount
Diffstat (limited to 'contrib')
| -rw-r--r-- | contrib/Makefile.am | 3 | ||||
| -rw-r--r-- | contrib/fuse-lib/mount.c | 94 | ||||
| -rw-r--r-- | contrib/fuse-util/COPYING | 340 | ||||
| -rw-r--r-- | contrib/fuse-util/Makefile.am | 12 | ||||
| -rw-r--r-- | contrib/fuse-util/fusermount.c | 965 | ||||
| -rw-r--r-- | contrib/fuse-util/mount_util.h | 17 | 
6 files changed, 1428 insertions, 3 deletions
diff --git a/contrib/Makefile.am b/contrib/Makefile.am new file mode 100644 index 00000000000..a3d5cfbf855 --- /dev/null +++ b/contrib/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = fuse-util + +CLEANFILES = diff --git a/contrib/fuse-lib/mount.c b/contrib/fuse-lib/mount.c index c9e2035d467..c6de43607f3 100644 --- a/contrib/fuse-lib/mount.c +++ b/contrib/fuse-lib/mount.c @@ -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 diff --git a/contrib/fuse-util/COPYING b/contrib/fuse-util/COPYING new file mode 100644 index 00000000000..d60c31a97a5 --- /dev/null +++ b/contrib/fuse-util/COPYING @@ -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. diff --git a/contrib/fuse-util/Makefile.am b/contrib/fuse-util/Makefile.am new file mode 100644 index 00000000000..06b6cb6da72 --- /dev/null +++ b/contrib/fuse-util/Makefile.am @@ -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 = diff --git a/contrib/fuse-util/fusermount.c b/contrib/fuse-util/fusermount.c new file mode 100644 index 00000000000..c3ecc86cc44 --- /dev/null +++ b/contrib/fuse-util/fusermount.c @@ -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; +} diff --git a/contrib/fuse-util/mount_util.h b/contrib/fuse-util/mount_util.h new file mode 100644 index 00000000000..cf54d9d0d02 --- /dev/null +++ b/contrib/fuse-util/mount_util.h @@ -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);  | 
