mount.c revision 9acbbeaf2a1ffe5c14b244867d427714fab43c5c
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <alloca.h>
#include <assert.h>
#include <ctype.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <sys/lx_autofs.h>
#include <sys/lx_debug.h>
#include <sys/lx_mount.h>
/*
* support definitions
*/
union fh_buffer {
};
typedef enum mount_opt_type {
MOUNT_OPT_INVALID = 0,
typedef struct mount_opt {
char *mo_name;
} mount_opt_t;
/*
* Globals
*/
mount_opt_t lofs_options[] = {
{ NULL, MOUNT_OPT_INVALID }
};
mount_opt_t lx_proc_options[] = {
{ NULL, MOUNT_OPT_INVALID }
};
mount_opt_t lx_autofs_options[] = {
{ LX_MNTOPT_FD, MOUNT_OPT_UINT },
{ LX_MNTOPT_PGRP, MOUNT_OPT_UINT },
};
/*
* i_lx_opt_verify() - Check the mount options.
*
* You might wonder why we're being so strict about the mount options
* we allow. The reason is that normally all mount option verification
* is done by the Solaris userland mount command. Once mount options
* are passed to the kernel, invalid options are simply ignored. So
* if we actually want to catch requests for functionality that we
* don't support, or if we want to make sure that we don't randomly
* enable options that we haven't check to make sure they have the
* same syntax on Linux and Solaris, we need to reject any options
* we don't know to be ok here.
*/
static int
{
int opt_len, i;
/* If no options were specified, there's no problem. */
if (opts_len == 0)
return (1);
/* If no options are allowed, fail. */
return (0);
/* Don't accept leading or trailing ','. */
return (0);
/* Don't accept sequential ','. */
for (i = 1; i < opts_len; i++)
return (0);
/*
* We're going to use strtok() which modifies the target
* string so make a temporary copy.
*/
return (-1);
/* Verify each prop one at a time. */
for (;;) {
char *ovalue;
int ovalue_len, mo_len;
/* If the options is too short don't bother comparing */
/* Keep trying to find a match. */
continue;
}
/* Compare the option to an allowed option. */
/* Keep trying to find a match. */
continue;
}
/* The option doesn't take a value. */
/* This option is ok. */
break;
} else {
/* Keep trying to find a match. */
continue;
}
}
/* This options takes a value. */
/* Keep trying to find a match. */
continue;
}
/* We have an option match. Verify option value. */
/* Value can't be zero length string. */
if (ovalue_len == 0)
return (0);
int j;
/* Verify that value is an unsigned int. */
for (j = 0; j < ovalue_len; j++)
return (0);
} else {
/* Unknown option type specified. */
assert(0);
}
/* The option is ok. */
break;
}
/* If there were no matches this is an unsupported option. */
return (0);
/* This option is ok, move onto the next option. */
break;
};
/* We verified all the options. */
return (1);
}
static int
{
if (buf[0] == '\0') {
fmt_str = "%s";
} else {
fmt_str = ",%s";
}
/*LINTED*/
return (-EOVERFLOW);
return (0);
}
static int
{
if (buf[0] == '\0') {
fmt_str = "%s=%d";
} else {
fmt_str = ",%s=%d";
}
/*LINTED*/
return (-EOVERFLOW);
return (0);
}
static int
{
/* Sanity check the incomming Linux request. */
(lx_nmd->nmd_acdirmax < 0)) {
return (-EINVAL);
}
/*
* Additional sanity checks of incomming request.
*
* Some of the sanity checks below should probably return
* EINVAL (or some other error code) instead or ENOTSUP,
* but without experiminting on Linux to see how it
* deals with certain strange values there is no way
* to really know what we should return, hence we return
* ENOTSUP to tell us that eventually if we see some
* application hitting the problem we can go to a real
* Linux system, figure out how it deals with the situation
* and update our code to handle it in the same fashion.
*/
lx_unsupported("unsupported nfs mount request, "
"unrecognized NFS mount structure: %d\n",
return (-ENOTSUP);
}
lx_unsupported("unsupported nfs mount request, "
return (-ENOTSUP);
}
lx_unsupported("unsupported nfs mount request, "
"transport address family: 0x%x\n",
return (-ENOTSUP);
}
lx_unsupported("unsupported nfs mount request, "
"nfs file handle length: 0x%x\n",
return (-ENOTSUP);
}
for (i = 0; i < LX_NMD_MAXHOSTNAMELEN; i++) {
break;
}
if (i == 0) {
lx_unsupported("unsupported nfs mount request, "
"no hostname specified\n");
return (-ENOTSUP);
}
if (i == LX_NMD_MAXHOSTNAMELEN) {
lx_unsupported("unsupported nfs mount request, "
"hostname not terminated\n");
return (-ENOTSUP);
}
if (lx_nmd->nmd_namlen < i) {
lx_unsupported("unsupported nfs mount request, "
return (-ENOTSUP);
}
lx_unsupported("unsupported nfs mount request, "
return (-ENOTSUP);
}
/* Initialize and clear the output structure pointers passed in. */
/* Check if we're using tcp. */
/*
* These seem to be the default flags used by Solaris for v2 and v3
* nfs mounts.
*
* Don't bother with NFSMNT_TRYRDMA since we always specify a
* transport (either udp or tcp).
*/
/* Translate some Linux mount flags into Solaris mount flags. */
options, options_size)) != 0)
return (rv);
/* Set the v3 file handle info. */
} else {
/*
* Assume nfs v2. Note that this could also be a v1
* mount request but there doesn't seem to be any difference
* in the parameters passed to the Linux mount system
* call for v1 or v2 mounts so there is no way of really
* knowing.
*/
options, options_size)) != 0)
return (rv);
/* Solaris seems to add this flag when using v2. */
/* Set the v2 file handle info. */
}
/*
* We can't use getnetconfig() here because there is no netconfig
* database in linux.
*/
if (use_tcp) {
/*
* TCP uses NC_TPI_COTS_ORD semantics.
*/
options, options_size)) != 0)
return (rv);
return (-errno);
} else {
/*
* Assume UDP. UDP uses NC_TPI_CLTS semantics.
*/
options, options_size)) != 0)
return (rv);
return (-errno);
}
/* Set the server address. */
sizeof (struct sockaddr_in);
/* Set the server hostname string. */
/* Translate Linux nfs mount parameters into Solaris mount options. */
options, options_size)) != 0)
return (rv);
}
options, options_size)) != 0)
return (rv);
}
options, options_size)) != 0)
return (rv);
options, options_size)) != 0)
return (rv);
options, options_size)) != 0)
return (rv);
options, options_size)) != 0)
return (rv);
options, options_size)) != 0)
return (rv);
options, options_size)) != 0)
return (rv);
/* We only support nfs with a security type of AUTH_SYS. */
nfs_args_secdata->flags = 0;
nfs_args_secdata->uid = 0;
/*
* The Linux nfs mount command seems to pass an open socket fd
* to the kernel during the mount system call. We don't need
* this fd on Solaris so just close it.
*/
return (0);
}
int
{
/* Linux input arguments. */
/* Variables needed for all mounts. */
/* Variables needed for nfs mounts. */
struct netbuf nfs_args_addr;
struct knetconfig nfs_args_knconf;
union fh_buffer nfs_args_fh;
struct sec_data nfs_args_secdata;
int sdatalen = 0;
/* Initialize Solaris mount arguments. */
options[0] = '\0';
sdatalen = 0;
/* Copy in parameters that are always present. */
return (-EFAULT);
return (-EFAULT);
return (-EFAULT);
/* Make sure we support the requested mount flags. */
if ((flags & ~LX_MS_SUPPORTED) != 0) {
"unsupported mount flags: 0x%x", flags);
return (-ENOTSUP);
}
/* Do filesystem specific mount work. */
if (flags & LX_MS_BIND) {
/* If MS_BIND is set, we turn this into a lofs mount. */
/* Copy in Linux mount options. */
return (-EFAULT);
}
/* Verify Linux mount options. */
lx_unsupported("unsupported lofs mount options");
return (-ENOTSUP);
}
/* Translate proc mount requests to lx_proc requests. */
/* Copy in Linux mount options. */
return (-EFAULT);
}
/* Verify Linux mount options. */
lx_unsupported("unsupported lx_proc mount options");
return (-ENOTSUP);
}
/* Translate proc mount requests to lx_afs requests. */
/* Copy in Linux mount options. */
return (-EFAULT);
}
/* Verify Linux mount options. */
lx_unsupported("unsupported lx_autofs mount options");
return (-ENOTSUP);
}
/*
* Copy in Linux mount options. Note that for Linux
* nfs mounts the mount options pointer (which normally
* points to a string) points to a structure.
*/
return (-errno);
/*
* For Solaris nfs mounts, the kernel expects a special
* strucutre, but a pointer to this structure is passed
* in via an extra parameter (sdataptr below.)
*/
return (rv);
/*
* For nfs mounts we need to tell the mount system call
* to expect extra parameters.
*/
} else {
"unsupported mount filesystem type: %s", fstype);
return (-ENOTSUP);
}
/* Convert some Linux flags to Solaris flags. */
if (flags & LX_MS_RDONLY)
if (flags & LX_MS_NOSUID)
if (flags & LX_MS_REMOUNT)
sflags |= MS_REMOUNT;
/* Convert some Linux flags to Solaris option strings. */
if ((flags & LX_MS_NODEV) &&
return (rv);
if ((flags & LX_MS_NOEXEC) &&
return (rv);
if ((flags & LX_MS_NOATIME) &&
return (rv);
}
/*
* umount() is identical, though it is implemented on top of umount2() in
* Solaris so it cannot be a pass-thru system call.
*/
int
{
}
/*
* The Linux umount2() system call is identical but has a different value for
* MNT_FORCE (the logical equivalent to MS_FORCE).
*/
#define LX_MNT_FORCE 0x1
int
{
int flags = 0;
if (p2 & ~LX_MNT_FORCE)
return (-EINVAL);
if (p2 & LX_MNT_FORCE)
}