mount.c revision 87c584d28b917037834264beb248765bd95712f5
/*
* 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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* University Copyright- Copyright (c) 1982, 1986, 1988
* The Regents of the University of California
* All Rights Reserved
*
* University Acknowledgment- Portions of this document are derived from
* software developed by the University of California, Berkeley, and its
* contributors.
*/
/*
* mount
*/
#include <ctype.h>
#include <string.h>
#include <fcntl.h>
#include <signal.h>
#include <poll.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <locale.h>
#include <fslib.h>
static int ro = 0;
static int largefiles = 0; /* flag - add default nolargefiles to mnttab */
static int gflg = 0;
static int mflg = 0;
static int Oflg = 0;
static int qflg = 0;
static int checkislog(char *);
static void disable_logging(char *, char *);
static void enable_logging(char *, char *);
static void replace_opts(char *, int, char *, char *);
static int replace_opts_dflt(char *, int, const char *, const char *);
static void rpterr(char *, char *);
static void usage(void);
static char fstype[] = MNTTYPE_UFS;
static char opts[MAX_MNTOPT_STR];
#define NOMATCH (-1)
#define ONERROR (0) /* index within fop_subopts */
static struct fop_subopt {
char *str;
int flag;
} fop_subopt_list[] = {
};
/*
* Check if the specified filesystem is already mounted.
*/
static boolean_t
{
return (B_FALSE);
break;
}
}
return (found);
}
/*
* Find opt in mntopt
*/
static char *
{
while (*mntopt) {
return (mntopt);
}
return (NULL);
}
int
{
int c;
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void) textdomain(TEXT_DOMAIN);
if (myname)
myname++;
else
opts[0] = '\0';
/*
* Set options
*/
switch (c) {
case 'g':
gflg++;
break;
case 'o':
sizeof (opts)) {
"argument too long\n"));
}
break;
case 'O':
Oflg++;
break;
case 'r':
ro++;
break;
case 'm':
mflg++;
break;
case 'q':
qflg++;
break;
default:
usage();
}
}
usage();
/*
* Process options. The resulting options string overwrites the
* original.
*
* XXX: This code doesn't do a good job of resolving options that are
* specified multiple times or that are given in conflicting
* forms (e.g., both "largefiles" and "nolargefiles"). It also
* doesn't produce well defined behavior for options that may
* also be specified as flags (e.g, "-r" and "ro"/"rw") when both
* are present.
*
* The proper way to deal with such conflicts is to start with
* the default value (i.e., the one if no flag or option is
* specified), override it with the last mentioned option pair
* in the -o option string, and finally, override that with
* the flag value. This allows "mount -r" command to mount a
*/
mflg++;
" global filesystem\n"));
exit(32);
}
}
return (0);
}
static void
{
/* No error */
return;
/* ioctl returned error */
if (ret == -1)
return;
/* Some more info */
case FIOLOG_ENONE :
if (flp->nbytes_requested &&
" resized from %d bytes to %d bytes.\n"),
flp->nbytes_actual);
}
return;
case FIOLOG_ETRANS :
" is already enabled.\n"));
" commands metadetach(1M)"
" or metaclear(1M).\n"));
break;
case FIOLOG_EROFS :
"only.\n"));
"option described in mount_ufs(1M).\n"));
break;
case FIOLOG_EULOCK :
"described in lockfs(1M).\n"));
break;
case FIOLOG_EWLOCK :
" write locked.\n"));
"described in lockfs(1M).\n"));
break;
case FIOLOG_ECLEAN :
" stable.\n"));
" for fsck(1M).\n"));
break;
case FIOLOG_ENOULOCK :
" unlocked.\n"));
"described in lockfs(1M).\n"));
break;
default :
break;
}
}
static int
checkislog(char *mp)
{
int fd;
islog = 0;
return ((int)islog);
}
static void
{
if (fd == -1) {
return;
}
fl.nbytes_requested = 0;
fl.nbytes_actual = 0;
if (ret == -1)
/* is logging enabled? */
/* report errors, if any */
}
static void
{
if (fd == -1) {
return;
}
if (ret == -1)
/* is logging enabled? */
/* report errors, if any */
}
/*
* attempt to mount file system, return errno or 0
*/
void
{
char opt[MAX_MNTOPT_STR];
char opt2[MAX_MNTOPT_STR];
int flags = MS_OPTIONSTR;
int need_separator = 0;
int mount_attempts = 5;
opt2[0] = '\0';
}
}
while (*opts != '\0') {
char *argval;
case ONERROR:
if (argval) {
struct fop_subopt *s;
int found = 0;
for (s = fop_subopt_list;
s++) {
found = 1;
}
}
if (!found) {
usage();
}
if (need_separator)
need_separator = 1;
} else {
}
break;
case NOMATCH:
default:
if (argval) {
if (need_separator)
need_separator = 1;
}
break;
}
}
if (*opt2 != '\0')
errno = 0;
if (mflg)
flags |= MS_NOMNTTAB;
if (flags & MS_REMOUNT) {
}
/*
* For global filesystems we want to pass in logging option
* so that it shows up in the mnttab of all nodes. We add
* logging option if its not specified.
*/
} else {
/*
* Turn off logging for read only global mounts.
* It was set to logging as default above.
*/
}
}
/*
* Because of bug 6176743, any attempt to mount any
* filesystem could fail for reasons described in that
* bug. We're trying to detect that situation here by
* checking that the filesystem we're mounting is not
* code can be removed.
*/
mount_attempts-- > 0) {
goto again;
}
}
exit(32);
}
else
}
if (!qflg) {
}
/* update mnttab file if necessary */
if (!mflg) {
struct mnttagdesc mtdesc;
int fd;
exit(32);
/* do tag ioctl */
exit(32);
exit(32);
}
}
}
exit(0);
}
/*
* same as findopt but remove the option from the option string and return
* true or false
*/
static int
{
int has;
return (has);
}
/*
* remove an option string from the option list
*/
static void
{
char *str;
char *optstart;
str++)
/* NULL */;
if (*str == ',') {
str++;
optstart--;
}
;
}
}
/*
* mnt->mnt_ops has un-eaten opts, opts is the original opts list.
* Set mnt->mnt_opts to the original, the kernel will then remove
* the ones it cannot deal with.
* Set "opts" to the the original options for later comparison in
* cmp_....(). But strip the options which aren't returned by
* the kernel: "noglobal", "global" and "quota".
* And strip the options which aren't set through mount: "logging",
* "nologging" from those passed to mount(2).
*/
static void
{
/*
* Options not passed to the kernel and possibly not returned;
* these are dealt with using ioctl; and the ioctl may fail.
*/
/*
* options from main(); except for the option "f" and "remount".
*/
}
static void
usage(void)
{
"ufs usage:\n"
"mount [-F ufs] [generic options] [-o suboptions] {special | mount_point}\n"));
"\tsuboptions are: \n"
"\t ro,rw,nosuid,remount,f,m,\n"
"\t global,noglobal,\n"
"\t largefiles,nolargefiles,\n"
"\t forcedirectio,noforcedirectio\n"
"\t logging,nologging,\n"
"\t nbmand,nonbmand,\n"
"\t onerror[={panic | lock | umount}]\n"));
exit(32);
}
/*
* Returns the next option in the option string.
*/
static char *
getnextopt(char **p)
{
char *cp = *p;
char *retstr;
cp++;
cp++;
/* strip empty options */
while (*cp == ',') {
*cp = '\0';
cp++;
}
*p = cp;
return (retstr);
}
/*
* "trueopt" and "falseopt" are two settings of a Boolean option.
* If "flag" is true, forcibly set the option to the "true" setting; otherwise,
* if the option isn't present, set it to the false setting.
*/
static void
{
char *f;
char *tmpoptsp;
int found;
found = 0;
if (options[0] != '\0')
found++;
if (flag)
else
found++;
} else
}
if (!found) {
if (options[0] != '\0')
}
}
/*
* "trueopt" and "falseopt" are two settings of a Boolean option and "dflt" is
* a default value for the option. Rewrite the contents of options to include
* only the last mentioned occurrence of trueopt and falseopt. If neither is
* mentioned, append one or the other to options, according to the value of
* dflt. Return the resulting value of the option in boolean form.
*
* Note that the routine is implemented to have the resulting occurrence of
* trueopt or falseopt appear at the end of the resulting option string.
*
* N.B. This routine should take the place of replace_opts, but there are
* probably some compatibility issues to resolve before doing so. It
* should certainly be used to handle new options that don't have
* compatibility issues.
*/
static int
char *options,
int dflt,
const char *trueopt,
const char *falseopt)
{
char *f;
char *tmpoptsp;
int last;
/*
* Transfer the contents of options to tmptopts, in anticipation of
* copying a subset of the contents back to options.
*/
/*
* Loop over each option value, copying non-matching values back into
* options and updating the last seen occurrence of trueopt or
* falseopt.
*/
/* Check for both forms of the option of interest. */
last = 1;
last = 0;
} else {
/* Not what we're looking for; transcribe. */
if (options[0] != '\0')
}
}
/*
* Transcribe the correct form of the option of interest, using the
* default value if it wasn't overwritten above.
*/
if (options[0] != '\0')
return (last);
}
static void
{
switch (errno) {
case EPERM:
myname);
break;
case ENXIO:
break;
case ENOTDIR:
"%s: %s not a directory\n\tor a component of %s is not a directory\n"),
break;
case ENOENT:
"%s: %s or %s, no such file or directory\n"),
break;
case EINVAL:
break;
case EBUSY:
gettext("%s: %s is already mounted or %s is busy\n"),
break;
case ENOTBLK:
break;
case EROFS:
break;
case ENOSPC:
"%s: The state of %s is not okay\n"
"mount: Please run fsck and try again\n"));
break;
case EFBIG:
"%s: Large files may be present on %s,\n"
"\tand it was attempted to be mounted nolargefiles\n"),
break;
default:
}
}