mount.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* Portions of this source code were derived from Berkeley 4.3 BSD
* under license from the Regents of the University of California.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
*
* mount.c
*
* Cachefs mount program.
*/
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <stdarg.h>
#include <unistd.h>
#include <limits.h>
#include <errno.h>
#include <wait.h>
#include <ctype.h>
#include <fcntl.h>
#include <fslib.h>
#include <kstat.h>
#include <nfs/nfs_clnt.h>
#include "../common/cachefsd.h"
char *cfs_opts[] = {
#define CFSOPT_BACKFSTYPE 0
"backfstype",
#define CFSOPT_CACHEDIR 1
"cachedir",
#define CFSOPT_CACHEID 2
"cacheid",
#define CFSOPT_BACKPATH 3
"backpath",
#define CFSOPT_WRITEAROUND 4
"write-around",
#define CFSOPT_NONSHARED 5
"non-shared",
#define CFSOPT_DISCONNECTABLE 6
"disconnectable",
#define CFSOPT_SOFT 7
"soft",
#define CFSOPT_NOCONST 8
"noconst",
#define CFSOPT_CODCONST 9
"demandconst",
#define CFSOPT_LOCALACCESS 10
"local-access",
#define CFSOPT_LAZYMOUNT 11
"lazy-mount",
#define CFSOPT_RW 12
"rw",
#define CFSOPT_RO 13
"ro",
#define CFSOPT_SUID 14
"suid",
#define CFSOPT_NOSUID 15
"nosuid",
#define CFSOPT_REMOUNT 16
"remount",
#define CFSOPT_FGSIZE 17
"fgsize",
#define CFSOPT_POPSIZE 18
"popsize",
#define CFSOPT_ACREGMIN 19
"acregmin",
#define CFSOPT_ACREGMAX 20
"acregmax",
#define CFSOPT_ACDIRMIN 21
"acdirmin",
#define CFSOPT_ACDIRMAX 22
"acdirmax",
#define CFSOPT_ACTIMEO 23
"actimeo",
#define CFSOPT_SLIDE 24
"slide",
#define CFSOPT_NOSETSEC 25
"nosec", /* XXX should we use MNTOPT_NOTSETSEC? */
#define CFSOPT_LLOCK 26
"llock",
#define CFSOPT_NONOTIFY 27
"nonotify",
#define CFSOPT_SNR 28
"snr",
#define CFSOPT_NOFILL 29
"nofill",
#ifdef CFS_NFSV3_PASSTHROUGH
#define CFSOPT_NFSV3PASSTHROUGH 30
"nfsv3pass",
#endif /* CFS_NFSV3_PASSTHROUGH */
};
/* XXX - and should be cachefs */
/* forward references */
char *get_back_fsid(char *specp);
char *get_cacheid(char *, char *);
int pingserver(char *backmntp);
int check_cache(char *cachedirp);
int nomnttab;
int quiet;
/*
*
* main
*
* Description:
* Main routine for the cachefs mount program.
* Arguments:
* argc number of command line arguments
* argv list of command line arguments
* Returns:
* Returns 0 for success, 1 an error was encountered.
* Preconditions:
*/
{
char *myname;
char *optionp;
char *opigp;
int mflag;
int readonly;
struct cachefs_mountargs margs;
char *backfstypep;
char *reducep;
char *specp;
int xx;
int stat_loc;
char *newargv[20];
char *mntp;
int mounted;
int c;
int lockid;
int Oflg;
char *strp;
char servname[33];
int notify = 1;
struct mnttagdesc mtdesc;
char mops[MAX_MNTOPT_STR];
char cfs_nfsv4ops[MAX_MNTOPT_STR];
int nfsv3pass = 0;
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void) textdomain(TEXT_DOMAIN);
if (argv[0]) {
if (myname)
myname++;
else
} else {
myname = "path unknown";
}
nomnttab = 0;
quiet = 0;
readonly = 0;
Oflg = 0;
cfs_nfsv4ops[0] = '\0';
/* process command line options */
switch (c) {
nomnttab = 1;
break;
case 'o':
break;
case 'O':
Oflg++;
break;
case 'r': /* read only mount */
readonly = 1;
break;
case 'q':
quiet = 1;
break;
default:
usage("invalid option");
return (1);
}
}
/* if -o not specified */
return (1);
}
/* verify special device and mount point are specified */
return (1);
}
/* Store mount point and special device. */
/* Initialize default mount values */
margs.cfs_acregmin = 0;
margs.cfs_acregmax = 0;
margs.cfs_acdirmin = 0;
margs.cfs_acdirmax = 0;
if (nomnttab)
mflag |= MS_NOMNTTAB;
backfstypep = NULL;
/* process -o options */
if (xx) {
return (1);
}
/* backfstype has to be specified */
if (backfstypep == NULL) {
return (1);
}
return (1);
}
/* set default write mode if not specified */
(CFS_WRITE_AROUND|CFS_NONSHARED)) == 0) {
}
/* if read-only was specified with the -r option */
if (readonly) {
}
/* if overlay was specified with -O option */
if (Oflg) {
mflag |= MS_OVERLAY;
}
/* get the fsid of the backfs and the cacheid */
return (1);
}
/*
* If using this cachedir to mount a file system for the first time
* after reboot, the ncheck for the sanity of the cachedir
*/
return (1);
/* get the front file system cache id if necessary */
return (1);
}
}
/* lock the cache directory shared */
if (lockid == -1) {
/* exit if could not get the lock */
return (1);
}
/* if no mount point was specified and we are not remounting */
mounted = 0;
(((mflag & MS_REMOUNT) == 0) ||
/* if a disconnectable mount */
xx = 0;
/* see if the server is alive */
}
/* attempt to mount the back file system */
if (xx == 0) {
/*
* nfs mount exits with a value of 32 if a timeout
* error occurs trying the mount.
*/
return (1);
}
if (xx == 0)
mounted = 1;
}
}
/*
* At this point the back file system should be mounted.
* Get NFS version information for the back filesystem if
* it is NFS. The version information is required
* because NFS version 4 is incompatible with cachefs
* and we provide pass-through support for NFS version 4
* with cachefs, aka the cachefs mount is installed but
* there is no caching. This is indicated to the kernel
* during the mount by setting the CFS_BACKFS_NFSV4 flag.
*/
switch (nfsvers) {
case 2:
break;
case 3:
if (nfsv3pass) {
/* Force pass through (for debugging) */
cfs_nfsv4ops) != 0) {
goto clean_backmnt;
}
}
break;
case 4:
/*
* overwrite old option flags with NFSv4 flag.
* Note that will also operate in strict
* consistency mode. Clean up the option string
* to get rid of the cachefs-specific options
* to be in sync with the opt flags, otherwise
* these can make it into the mnttab and cause
* problems (esp. the disconnected option).
*/
goto clean_backmnt;
}
break;
default:
/* error, unknown version */
goto clean_backmnt;
}
}
/*
* Grab server name from special file arg if it is there or set
* server name to "server unknown".
*/
} else {
*strp = '\0';
/*
* The rest of the special file arg is the name of
* the back filesystem.
*/
strp++;
}
/* mount the cache file system */
if (nfsvers_error) {
} else {
}
/* try to unmount the back file system if we mounted it */
if (mounted) {
xx = 1;
/* fork */
return (1);
}
/* if the child */
if (pid == 0) {
/* do the unmount */
}
/* else if the parent */
else {
wait(0);
}
}
return (1);
}
/* release the lock on the cache directory */
/* record the mount information in the fscache directory */
/* notify the daemon of the mount */
if (notify)
/* update mnttab file if necessary */
if (!nomnttab) {
/*
* If we added the back file system, tag it with ignore,
* however, don't fail the mount after its done
* if the tag can't be added (eg., this would cause
* automounter problems).
*/
if (mounted) {
return (1);
mnt.mnt_mountp) == 0) {
/* found it, do tag ioctl */
MNTIOC_SETTAG, &mtdesc);
break;
}
}
}
}
/* return success */
return (0);
}
/*
*
* usage
*
* Description:
* Prints a short usage message.
* Arguments:
* msgp message to include with the usage message
* Returns:
* Preconditions:
*/
void
{
if (msgp) {
}
gettext("Usage: mount -F cachefs [generic options] "
"-o backfstype=file_system_type[FSTypespecific_options] "
"special mount_point\n"));
}
/*
*
* pr_err
*
* Description:
* Prints an error message to stderr.
* Arguments:
* fmt printf style format
* ... arguments for fmt
* Returns:
* Preconditions:
* precond(fmt)
*/
void
{
}
/*
*
* set_cfs_args
*
* Description:
* Parse the comma delimited set of options specified by optionp
* and puts the results in margsp, mflagp, and backfstypepp.
* A string is constructed of options which are not specific to
* cfs and is placed in reducepp.
* Pointers to strings are invalid if this routine is called again.
* No initialization is done on margsp, mflagp, or backfstypepp.
* Arguments:
* optionp string of comma delimited options
* margsp option results for the mount dataptr arg
* mflagp option results for the mount mflag arg
* backfstypepp set to name of back file system type
* reducepp set to the option string without cfs specific options
* Returns:
* Returns 0 for success, -1 for an error.
* Preconditions:
* precond(optionp)
* precond(margsp)
* precond(mflagp)
* precond(backfstypepp)
* precond(reducepp)
*/
int
{
int badopt;
int ret;
int o_backpath = 0;
int o_writemode = 0;
int xx;
char *pbuf;
/* free up any previous options */
/* make a copy of the options so we can modify it */
return (-1);
}
*reducep = '\0';
/* parse the options */
badopt = 0;
ret = 0;
while (*strp) {
case CFSOPT_BACKFSTYPE:
badopt = 1;
else
*backfstypepp = valp;
break;
case CFSOPT_CACHEDIR:
badopt = 1;
else {
if (valp[0] != '/') {
badopt = 1;
break;
}
badopt = 1;
break;
}
}
}
break;
case CFSOPT_CACHEID:
badopt = 1;
break;
}
badopt = 1;
break;
}
break;
case CFSOPT_BACKPATH:
badopt = 1;
else {
o_backpath = 1;
}
break;
case CFSOPT_WRITEAROUND:
o_writemode++;
break;
case CFSOPT_NONSHARED:
o_writemode++;
break;
case CFSOPT_NOCONST:
break;
case CFSOPT_CODCONST:
break;
case CFSOPT_LOCALACCESS:
break;
case CFSOPT_NOSETSEC:
break;
case CFSOPT_LLOCK:
break;
case CFSOPT_REMOUNT:
*mflagp |= MS_REMOUNT;
break;
case CFSOPT_SLIDE:
break;
case CFSOPT_FGSIZE:
badopt = 1;
else
break;
case CFSOPT_POPSIZE:
badopt = 1;
else
break;
case CFSOPT_ACREGMIN:
badopt = 1;
else
break;
case CFSOPT_ACREGMAX:
badopt = 1;
else
break;
case CFSOPT_ACDIRMIN:
badopt = 1;
else
break;
case CFSOPT_ACDIRMAX:
badopt = 1;
else
break;
case CFSOPT_ACTIMEO:
badopt = 1;
else {
}
/*
* Note that we do not pass the actimeo options
* to the back file system. This change was
* made for Chart. Chart needs noac or actimeo=0
* so it makes no sense to pass these options on.
* In theory it should be okay to not pass these
* options on for regular cachefs mounts since
* cachefs perform the required attribute caching.
*/
break;
#if 0
case CFSOPT_LAZYMOUNT:
break;
#endif
case CFSOPT_DISCONNECTABLE:
case CFSOPT_SNR:
break;
case CFSOPT_NOFILL:
break;
case CFSOPT_SOFT:
break;
case CFSOPT_NONOTIFY:
*notifyp = 0;
break;
#ifdef CFS_NFSV3_PASSTHROUGH
case CFSOPT_NFSV3PASSTHROUGH:
*nfsv3pass = 1;
break;
#endif /* CFS_NFSV3_PASSTHROUGH */
default:
/*
* unknown or vfs layer option, save for the back
* file system
*/
break;
}
/* if a lexical error occurred */
if (badopt) {
savep);
badopt = 0;
ret = -1;
}
}
/*
* Should mount backfs soft if disconnectable & non-shared options
* are used. NFS soft option allows reads and writes to TIMEOUT
* when the server is not responding, which is crucial for
* disconnectable option to work all the time in non-shared mode.
*
* Should mount backfs semisoft if disconnectable & write-around
* are used. NFS semisoft option allows reads to TIMEOUT and
* write to block when the server is not responding, which is
* good for write around option because it is shared.
*
* Since disconnectable and strict options are conflicting,
* when disconnectable option is used, default option is set to
* demandconst.
*/
}
else
/* not snr, no need to notify the cachefsd */
*notifyp = 0;
}
/* additional nfs options needed so disconnectable will work */
/*
* retry=0 so cachefs can mount if nfs mount fails
* even with this nfs takes 3 minutes to give up
* actimeo=0 because NFS does not pick up new ctime after
* rename
*/
}
/* check for conflicting options */
ret = -1;
}
ret = -1;
}
ret = -1;
}
" may be specified"));
ret = -1;
}
if (o_writemode > 1) {
"only one of write-around or non-shared"
" may be specified"));
ret = -1;
}
/* if an error occured */
if (ret)
return (-1);
/* if there are any options which are not mount specific */
if (*reducep)
else
/* return success */
return (0);
}
/*
*
* get_mount_point
*
* Description:
* Makes a suitable mount point for the back file system.
* The name of the mount point created is stored in a malloced
* buffer in pathpp
* Arguments:
* cachedirp the name of the cache directory
* specp the special name of the device for the file system
* pathpp where to store the mount point
* Returns:
* Returns 0 for success, -1 for an error.
* Preconditions:
* precond(cachedirp)
* precond(specp)
* precond(pathpp)
*/
int
{
char *strp;
char *namep;
int xx;
int index;
int max;
/* make a copy of the special device name */
return (-1);
}
/* convert the special device name into a file name */
*strp = '_';
}
/* get some space for the path name */
return (-1);
}
/* see if the mount directory is valid */
/* backfs can contain large files */
return (-1);
}
/* find a directory name we can use */
max = 10000;
/* construct a directory name to consider */
if (index == 1)
else
/* try to create the directory */
if (xx == 0) {
/* done if the create succeeded */
break;
}
}
/* if the search failed */
return (-1);
}
/* return success */
return (0);
}
int
{
int xx;
char *newargv[20];
int stat_loc;
/* get a suitable mount point */
if (xx)
return (1);
/* construct argument list for mounting the back file system */
xx = 1;
if (readonly)
if (nomnttab)
if (quiet)
if (reducep) {
}
/* fork */
return (1);
}
/* if the child */
if (pid == 0) {
/* do the mount */
}
/* else if the parent */
else {
/* wait for the child to exit */
return (1);
}
return (1);
}
if (xx) {
return (xx);
}
}
return (0);
}
/*
*
* doexec
*
* Description:
* Execs the specified program with the specified command line arguments.
* This function never returns.
* Arguments:
* fstype type of file system
* newargv command line arguments
* progp name of program to exec
* Returns:
* Preconditions:
* precond(fstype)
* precond(newargv)
*/
void
{
char alter_path[PATH_MAX];
/* build the full pathname of the fstype dependent command. */
/* if the program exists */
/* invoke the program */
/* if wrong permissions */
}
/* if it did not work and the shell might make it */
newargv[0] = "sh";
}
}
/* try the alternate path */
/* if wrong permissions */
}
/* if it did not work and the shell might make it */
newargv[0] = "sh";
}
exit(1);
}
/*
*
* get_back_fsid
*
* Description:
* Determines a unique identifier for the back file system.
* Arguments:
* specp the special file of the back fs
* Returns:
* Returns a malloc string which is the unique identifer
* or NULL on failure. NULL is only returned if malloc fails.
* Preconditions:
* precond(specp)
*/
char *
get_back_fsid(char *specp)
{
}
/*
*
* get_cacheid
*
* Description:
* Determines an identifier for the front file system cache.
* The returned string points to a static buffer which is
* overwritten on each call.
* The length of the returned string is < C_MAX_MOUNT_FSCDIRNAME.
* Arguments:
* fsidp back file system id
* mntp front file system mount point
* Returns:
* Returns a pointer to the string identifier, or NULL if the
* identifier was overflowed.
* Preconditions:
* precond(fsidp)
* precond(mntp)
*/
char *
{
char *c1;
/* strip off trailing space in mountpoint -- autofs fallout */
return (NULL);
if (*c1 == ' ')
*c1 = '\0';
return (NULL);
*c1 = '_';
return (buf);
}
/*
*
* check_cache
*
* Description:
* Checks the cache we are about to use.
* Arguments:
* cachedirp cachedirectory to check
* Returns:
* Returns 0 for success, -1 for an error.
* Preconditions:
*/
int
char *cachedirp;
{
char *fsck_argv[4];
int status = 0;
/* fork */
return (1);
}
if (pid == 0) {
/* do the fsck */
} else {
/* wait for the child to exit */
return (1);
}
return (1);
}
if (WEXITSTATUS(status) != 0) {
return (1);
}
}
return (0);
}
/*
*
* record_mount
*
* Description:
* Records mount information in a file in the fscache directory.
* Arguments:
* Returns:
* Preconditions:
*/
void
{
/* this file is < 2GB */
return;
}
if (specp) {
}
if (backfsp)
if (reducep)
}
int
{
int ret;
int xx;
int result;
char *hostp;
struct cachefsd_fs_mounted args;
/* get the host name */
if (xx == -1) {
return (1);
}
/* creat the connection to the daemon */
return (1);
}
if (retval != RPC_SUCCESS) {
return (1);
}
ret = 0;
return (ret);
}
/* returns 0 if the server is alive, -1 if an error */
int
pingserver(char *backmntp)
{
int ret;
int xx;
char *hostp;
char buf[MAXPATHLEN];
char *pc;
/* get the host name */
/* no host name, pretend it works */
return (0);
}
*pc = '\0';
/* create the connection to the mount daemon */
return (-1);
}
ret = 0;
/* see if the mountd responds */
TIMEOUT);
if (retval != RPC_SUCCESS) {
ret = -1;
}
return (ret);
}
/*
* first_time_ab : first time after boot - returns non-zero value
* if the cachedir is being used for the first time
* after the system reboot, otherwise zero.
*/
int
first_time_ab(char *buf)
{
char name[MAXPATHLEN];
int ufd;
return (1);
return (1);
return (1);
return (1);
if (get_boottime() != btime)
return (1);
return (0);
}
/*
* cachefs_get_back_nfsvers
*
* Returns: nfs version
*
* Params:
* cfs_backfs - backfile system mountpoint
* nomnttab - mnttab entry does not exist
*
* Uses the kstat interface to extract the nfs version for
* the mount.
*/
{
struct mntinfo_kstat mik;
/*
* Initialize kernel statistics facility.
*/
goto end;
}
/*
* Locate the mount information in the mnttab if the nomnttab
* flag is not set, otherwise look for the entry by doing
* stat'ting the mountpoint.
*/
if (!nomnttab) {
goto end;
}
continue;
}
break;
}
}
goto end;
} else {
}
}
/*
* Walk the kstat control structures to locate the
* statistics for the mounted backfilesystem.
*/
continue;
continue;
continue;
continue;
/*
* At this point we have located the
* kstat info for the mount, read the
* statistics and return version info.
*/
goto end;
}
break;
}
end:
if (kc)
if (mnttab)
return (nfsvers);
}
/*
* cfs_nfsv4_build_opts
*
* Returns: 0 on success, -1 on failure
*
* Params:
* optionp - original option pointer
* cfs_nfsv4ops - modified options for nfsv4 cachefs mount
*
* Parse the comma delimited set of options specified by optionp
* and clean out options that we don't want to use with NFSv4.
*/
int
{
char *optstrp;
char *strp;
char *savep;
char *valp;
/* Make a copy of the options so we can modify it */
return (-1);
}
/* Parse the options, cfs_nfsv4ops is initialized in main */
while (*strp) {
/* Ignore options that set cfs option flags */
case CFSOPT_WRITEAROUND:
case CFSOPT_NONSHARED:
case CFSOPT_NOCONST:
case CFSOPT_CODCONST:
case CFSOPT_LOCALACCESS:
case CFSOPT_NOSETSEC:
case CFSOPT_LLOCK:
case CFSOPT_SLIDE:
case CFSOPT_DISCONNECTABLE:
case CFSOPT_SNR:
case CFSOPT_NOFILL:
case CFSOPT_SOFT:
break;
default:
/*
* Copy in option for cachefs nfsv4 mount.
*/
savep);
break;
}
}
return (0);
}