4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 * The Regents of the University of California
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
47 #include <sys/mkdev.h>
48 #include <sys/param.h>
49 #include <sys/types.h>
50 #include <sys/mntent.h>
53 #define bcopy(f, t, n) memcpy(t, f, n)
54 #define bzero(s, n) memset(s, 0, n)
55 #define bcmp(s, d, n) memcmp(s, d, n)
57 #define index(s, r) strchr(s, r)
58 #define rindex(s, r) strrchr(s, r)
65 #include <sys/mnttab.h>
66 #include <sys/mount.h>
67 #include <sys/mntio.h>
69 #include <sys/fstyp.h>
71 #include <sys/vfstab.h>
72 #include <sys/filio.h>
73 #include <sys/fs/ufs_fs.h>
75 #include <sys/fs/ufs_mount.h>
76 #include <sys/fs/ufs_filio.h>
82 static int largefiles
= 0; /* flag - add default nolargefiles to mnttab */
88 #define NAME_MAX 64 /* sizeof "fstype myname" */
90 static int checkislog(char *);
91 static void disable_logging(char *, char *);
92 static int eatmntopt(struct mnttab
*, char *);
93 static void enable_logging(char *, char *);
94 static void fixopts(struct mnttab
*, char *);
95 static void mountfs(struct mnttab
*);
96 static void replace_opts(char *, int, char *, char *);
97 static void rmopt(struct mnttab
*, char *);
98 static void rpterr(char *, char *);
99 static void usage(void);
101 static char fstype
[] = MNTTYPE_UFS
;
102 static char opts
[MAX_MNTOPT_STR
];
103 static char typename
[NAME_MAX
], *myname
;
104 static char *fop_subopts
[] = { MNTOPT_ONERROR
, NULL
};
106 #define ONERROR (0) /* index within fop_subopts */
108 static struct fop_subopt
{
111 } fop_subopt_list
[] = {
112 { UFSMNT_ONERROR_PANIC_STR
, UFSMNT_ONERROR_PANIC
},
113 { UFSMNT_ONERROR_LOCK_STR
, UFSMNT_ONERROR_LOCK
},
114 { UFSMNT_ONERROR_UMOUNT_STR
, UFSMNT_ONERROR_UMOUNT
},
115 { NULL
, UFSMNT_ONERROR_DEFAULT
}
120 * Check if the specified filesystem is already mounted.
123 in_mnttab(char *mountp
)
127 struct mnttab mntent
;
129 if ((file
= fopen(MNTTAB
, "r")) == NULL
)
131 while (getmntent(file
, &mntent
) == 0) {
132 if (mntent
.mnt_mountp
!= NULL
&&
133 strcmp(mntent
.mnt_mountp
, mountp
) == 0 &&
134 mntent
.mnt_fstype
!= NULL
&&
135 strcmp(mntent
.mnt_fstype
, MNTTYPE_UFS
) == 0) {
148 findopt(char *mntopt
, char *opt
)
150 int nc
, optlen
= strlen(opt
);
153 nc
= strcspn(mntopt
, ", =");
154 if (strncmp(mntopt
, opt
, nc
) == 0)
158 mntopt
+= strspn(mntopt
, ", =");
164 main(int argc
, char *argv
[])
169 (void) setlocale(LC_ALL
, "");
170 #if !defined(TEXT_DOMAIN)
171 #define TEXT_DOMAIN "SYS_TEST"
173 (void) textdomain(TEXT_DOMAIN
);
175 myname
= strrchr(argv
[0], '/');
180 (void) snprintf(typename
, sizeof (typename
), "%s %s", fstype
, myname
);
188 while ((c
= getopt(argc
, argv
, "mo:pqrVO")) != EOF
) {
192 if (strlcpy(opts
, optarg
, sizeof (opts
)) >=
194 (void) fprintf(stderr
, gettext("option string "
195 "argument too long\n"));
220 if ((argc
- optind
) != 2)
223 mnt
.mnt_special
= argv
[optind
];
224 mnt
.mnt_mountp
= argv
[optind
+1];
225 mnt
.mnt_fstype
= fstype
;
228 * Process options. The resulting options string overwrites the
231 * XXX: This code doesn't do a good job of resolving options that are
232 * specified multiple times or that are given in conflicting
233 * forms (e.g., both "largefiles" and "nolargefiles"). It also
234 * doesn't produce well defined behavior for options that may
235 * also be specified as flags (e.g, "-r" and "ro"/"rw") when both
238 * The proper way to deal with such conflicts is to start with
239 * the default value (i.e., the one if no flag or option is
240 * specified), override it with the last mentioned option pair
241 * in the -o option string, and finally, override that with
242 * the flag value. This allows "mount -r" command to mount a
243 * file system read only that is listed rw in /etc/vfstab.
245 mnt
.mnt_mntopts
= opts
;
246 if (findopt(mnt
.mnt_mntopts
, "m"))
249 replace_opts(opts
, ro
, MNTOPT_RO
, MNTOPT_RW
);
250 replace_opts(opts
, largefiles
, MNTOPT_NOLARGEFILES
, MNTOPT_LARGEFILES
);
252 if (findopt(mnt
.mnt_mntopts
, MNTOPT_RQ
)) {
253 rmopt(&mnt
, MNTOPT_RQ
);
254 replace_opts(opts
, 1, MNTOPT_QUOTA
, MNTOPT_NOQUOTA
);
262 reportlogerror(int ret
, char *mp
, char *special
, char *cmd
, fiolog_t
*flp
)
265 if ((ret
!= -1) && (flp
->error
== FIOLOG_ENONE
))
268 /* logging was not enabled/disabled */
269 if (ret
== -1 || flp
->error
!= FIOLOG_ENONE
)
270 (void) fprintf(stderr
, gettext("Could not %s logging"
271 " for %s on %s.\n"), cmd
, mp
, special
);
273 /* ioctl returned error */
278 switch (flp
->error
) {
280 if (flp
->nbytes_requested
&&
281 (flp
->nbytes_requested
!= flp
->nbytes_actual
)) {
282 (void) fprintf(stderr
, gettext("The log has been"
283 " resized from %d bytes to %d bytes.\n"),
284 flp
->nbytes_requested
,
289 (void) fprintf(stderr
, gettext("Solaris Volume Manager logging"
290 " is already enabled.\n"));
291 (void) fprintf(stderr
, gettext("Please see the"
292 " commands metadetach(1M)"
293 " or metaclear(1M).\n"));
296 (void) fprintf(stderr
, gettext("File system is mounted read "
298 (void) fprintf(stderr
, gettext("Please see the remount "
299 "option described in mount_ufs(1M).\n"));
302 (void) fprintf(stderr
, gettext("File system is locked.\n"));
303 (void) fprintf(stderr
, gettext("Please see the -u option "
304 "described in lockfs(1M).\n"));
307 (void) fprintf(stderr
, gettext("The file system could not be"
308 " write locked.\n"));
309 (void) fprintf(stderr
, gettext("Please see the -w option "
310 "described in lockfs(1M).\n"));
313 (void) fprintf(stderr
, gettext("The file system may not be"
315 (void) fprintf(stderr
, gettext("Please see the -n option"
316 " for fsck(1M).\n"));
318 case FIOLOG_ENOULOCK
:
319 (void) fprintf(stderr
, gettext("The file system could not be"
321 (void) fprintf(stderr
, gettext("Please see the -u option "
322 "described in lockfs(1M).\n"));
325 (void) fprintf(stderr
, gettext("Unknown internal error"
326 " %d.\n"), flp
->error
);
337 fd
= open(mp
, O_RDONLY
);
339 (void) ioctl(fd
, _FIOISLOG
, &islog
);
345 enable_logging(char *mp
, char *special
)
350 fd
= open(mp
, O_RDONLY
);
355 fl
.nbytes_requested
= 0;
356 fl
.nbytes_actual
= 0;
357 fl
.error
= FIOLOG_ENONE
;
358 ret
= ioctl(fd
, _FIOLOGENABLE
, &fl
);
363 /* is logging enabled? */
364 islog
= checkislog(mp
);
366 /* report errors, if any */
367 if (ret
== -1 || !islog
)
368 reportlogerror(ret
, mp
, special
, "enable", &fl
);
372 disable_logging(char *mp
, char *special
)
377 fd
= open(mp
, O_RDONLY
);
382 fl
.error
= FIOLOG_ENONE
;
383 ret
= ioctl(fd
, _FIOLOGDISABLE
, &fl
);
388 /* is logging enabled? */
389 islog
= checkislog(mp
);
391 /* report errors, if any */
392 if (ret
== -1 || islog
)
393 reportlogerror(ret
, mp
, special
, "disable", &fl
);
398 * attempt to mount file system, return errno or 0
401 mountfs(struct mnttab
*mnt
)
403 char opt
[MAX_MNTOPT_STR
];
404 char opt2
[MAX_MNTOPT_STR
];
406 int flags
= MS_OPTIONSTR
;
407 struct ufs_args args
;
408 int need_separator
= 0;
409 int mount_attempts
= 5;
411 (void) bzero((char *)&args
, sizeof (args
));
412 (void) strcpy(opts
, mnt
->mnt_mntopts
);
415 flags
|= Oflg
? MS_OVERLAY
: 0;
416 flags
|= eatmntopt(mnt
, MNTOPT_RO
) ? MS_RDONLY
: 0;
417 flags
|= eatmntopt(mnt
, MNTOPT_REMOUNT
) ? MS_REMOUNT
: 0;
419 if (eatmntopt(mnt
, MNTOPT_NOINTR
))
420 args
.flags
|= UFSMNT_NOINTR
;
421 if (eatmntopt(mnt
, MNTOPT_INTR
))
422 args
.flags
&= ~UFSMNT_NOINTR
;
423 if (eatmntopt(mnt
, MNTOPT_SYNCDIR
))
424 args
.flags
|= UFSMNT_SYNCDIR
;
425 if (eatmntopt(mnt
, MNTOPT_FORCEDIRECTIO
)) {
426 args
.flags
|= UFSMNT_FORCEDIRECTIO
;
427 args
.flags
&= ~UFSMNT_NOFORCEDIRECTIO
;
429 if (eatmntopt(mnt
, MNTOPT_NOFORCEDIRECTIO
)) {
430 args
.flags
|= UFSMNT_NOFORCEDIRECTIO
;
431 args
.flags
&= ~UFSMNT_FORCEDIRECTIO
;
433 if (eatmntopt(mnt
, MNTOPT_NOSETSEC
))
434 args
.flags
|= UFSMNT_NOSETSEC
;
435 if (eatmntopt(mnt
, MNTOPT_LARGEFILES
))
436 args
.flags
|= UFSMNT_LARGEFILES
;
437 if (eatmntopt(mnt
, MNTOPT_NOLARGEFILES
))
438 args
.flags
&= ~UFSMNT_LARGEFILES
;
439 args
.flags
|= UFSMNT_LOGGING
; /* default is logging */
440 (void) eatmntopt(mnt
, MNTOPT_LOGGING
);
441 if (eatmntopt(mnt
, MNTOPT_NOLOGGING
))
442 args
.flags
&= ~UFSMNT_LOGGING
;
443 if (eatmntopt(mnt
, MNTOPT_NOATIME
))
444 args
.flags
|= UFSMNT_NOATIME
;
445 if (eatmntopt(mnt
, MNTOPT_DFRATIME
))
446 args
.flags
&= ~UFSMNT_NODFRATIME
;
447 if (eatmntopt(mnt
, MNTOPT_NODFRATIME
))
448 args
.flags
|= UFSMNT_NODFRATIME
;
450 while (*opts
!= '\0') {
453 switch (getsubopt(&opts
, fop_subopts
, &argval
)) {
456 struct fop_subopt
*s
;
459 for (s
= fop_subopt_list
;
462 if (strcmp(argval
, s
->str
) == 0) {
463 args
.flags
|= s
->flag
;
472 (void) strcat(opt2
, ",");
473 (void) strcat(opt2
, MNTOPT_ONERROR
);
474 (void) strcat(opt2
, "=");
475 (void) strcat(opt2
, argval
);
479 args
.flags
|= UFSMNT_ONERROR_DEFAULT
;
487 (void) strcat(opt2
, ",");
488 (void) strcat(opt2
, argval
);
497 (void) strcpy(opt
, opt2
);
499 if ((args
.flags
& UFSMNT_ONERROR_FLGMASK
) == 0)
500 args
.flags
|= UFSMNT_ONERROR_DEFAULT
;
502 (void) signal(SIGHUP
, SIG_IGN
);
503 (void) signal(SIGQUIT
, SIG_IGN
);
504 (void) signal(SIGINT
, SIG_IGN
);
507 flags
|= MS_DATA
| MS_OPTIONSTR
;
509 flags
|= MS_NOMNTTAB
;
510 if (flags
& MS_REMOUNT
) {
511 replace_opts(mnt
->mnt_mntopts
, 1, MNTOPT_RW
, MNTOPT_RO
);
515 again
: if (mount(mnt
->mnt_special
, mnt
->mnt_mountp
, flags
, fstype
,
516 &args
, sizeof (args
), mnt
->mnt_mntopts
, MAX_MNTOPT_STR
) != 0) {
517 if (errno
== EBUSY
&& !(flags
& MS_OVERLAY
)) {
519 * Because of bug 6176743, any attempt to mount any
520 * filesystem could fail for reasons described in that
521 * bug. We're trying to detect that situation here by
522 * checking that the filesystem we're mounting is not
523 * in /etc/mnttab yet. When that bug is fixed, this
524 * code can be removed.
526 if (!in_mnttab(mnt
->mnt_mountp
) &&
527 mount_attempts
-- > 0) {
528 (void) poll(NULL
, 0, 50);
532 rpterr(mnt
->mnt_special
, mnt
->mnt_mountp
);
536 if (!(flags
& MS_RDONLY
)) {
537 if (args
.flags
& UFSMNT_LOGGING
)
538 enable_logging(mnt
->mnt_mountp
, mnt
->mnt_special
);
540 disable_logging(mnt
->mnt_mountp
, mnt
->mnt_special
);
544 cmp_requested_to_actual_options(opts
, mnt
->mnt_mntopts
,
545 mnt
->mnt_special
, mnt
->mnt_mountp
);
548 if (checkislog(mnt
->mnt_mountp
)) {
549 /* update mnttab file if necessary */
552 struct mnttagdesc mtdesc
;
555 if (stat64(mnt
->mnt_mountp
, &statb
) != 0)
558 mtdesc
.mtd_major
= major(statb
.st_dev
);
559 mtdesc
.mtd_minor
= minor(statb
.st_dev
);
560 mtdesc
.mtd_mntpt
= mnt
->mnt_mountp
;
561 mtdesc
.mtd_tag
= MNTOPT_LOGGING
;
562 if ((fd
= open(MNTTAB
, O_RDONLY
, 0)) < 0)
564 if (ioctl(fd
, MNTIOC_SETTAG
, &mtdesc
) != 0) {
575 * same as findopt but remove the option from the option string and return
579 eatmntopt(struct mnttab
*mnt
, char *opt
)
583 has
= (findopt(mnt
->mnt_mntopts
, opt
) != NULL
);
589 * remove an option string from the option list
592 rmopt(struct mnttab
*mnt
, char *opt
)
597 while (optstart
= findopt(mnt
->mnt_mntopts
, opt
)) {
599 *str
!= ',' && *str
!= '\0' && *str
!= ' ';
604 } else if (optstart
!= mnt
->mnt_mntopts
) {
607 while (*optstart
++ = *str
++)
613 * mnt->mnt_ops has un-eaten opts, opts is the original opts list.
614 * Set mnt->mnt_opts to the original, the kernel will then remove
615 * the ones it cannot deal with.
616 * Set "opts" to the the original options for later comparison in
617 * cmp_....(). But strip the options which aren't returned by
618 * the kernel: "noglobal", "global" and "quota".
619 * And strip the options which aren't set through mount: "logging",
620 * "nologging" from those passed to mount(2).
623 fixopts(struct mnttab
*mnt
, char *opts
)
627 omnt
.mnt_mntopts
= opts
;
630 * Options not passed to the kernel and possibly not returned;
631 * these are dealt with using ioctl; and the ioctl may fail.
633 rmopt(&omnt
, MNTOPT_LOGGING
);
634 rmopt(&omnt
, MNTOPT_NOLOGGING
);
637 * Set the options for ``/etc/mnttab'' to be the original
638 * options from main(); except for the option "f" and "remount".
640 (void) strlcpy(mnt
->mnt_mntopts
, opts
, MAX_MNTOPT_STR
);
642 rmopt(mnt
, MNTOPT_REMOUNT
);
644 rmopt(&omnt
, MNTOPT_QUOTA
);
650 (void) fprintf(stdout
, gettext(
652 "mount [-F ufs] [generic options] [-o suboptions] {special | mount_point}\n"));
653 (void) fprintf(stdout
, gettext(
654 "\tsuboptions are: \n"
655 "\t ro,rw,nosuid,remount,f,m,\n"
656 "\t global,noglobal,\n"
657 "\t largefiles,nolargefiles,\n"
658 "\t forcedirectio,noforcedirectio\n"
659 "\t logging,nologging,\n"
660 "\t nbmand,nonbmand,\n"
661 "\t onerror[={panic | lock | umount}]\n"));
667 * Returns the next option in the option string.
675 while (*cp
&& isspace(*cp
))
678 while (*cp
&& *cp
!= ',')
680 /* strip empty options */
690 * "trueopt" and "falseopt" are two settings of a Boolean option.
691 * If "flag" is true, forcibly set the option to the "true" setting; otherwise,
692 * if the option isn't present, set it to the false setting.
695 replace_opts(char *options
, int flag
, char *trueopt
, char *falseopt
)
700 char tmptopts
[MNTMAXSTR
];
702 (void) strcpy(tmptopts
, options
);
704 (void) strcpy(options
, "");
707 for (f
= getnextopt(&tmpoptsp
); *f
; f
= getnextopt(&tmpoptsp
)) {
708 if (options
[0] != '\0')
709 (void) strcat(options
, ",");
710 if (strcmp(f
, trueopt
) == 0) {
711 (void) strcat(options
, f
);
713 } else if (strcmp(f
, falseopt
) == 0) {
715 (void) strcat(options
, trueopt
);
717 (void) strcat(options
, f
);
720 (void) strcat(options
, f
);
723 if (options
[0] != '\0')
724 (void) strcat(options
, ",");
725 (void) strcat(options
, flag
? trueopt
: falseopt
);
731 rpterr(char *bs
, char *mp
)
735 (void) fprintf(stderr
, gettext("%s: Insufficient privileges\n"),
739 (void) fprintf(stderr
, gettext("%s: %s no such device\n"),
743 (void) fprintf(stderr
,
745 "%s: %s not a directory\n\tor a component of %s is not a directory\n"),
749 (void) fprintf(stderr
, gettext(
750 "%s: %s or %s, no such file or directory\n"),
754 (void) fprintf(stderr
, gettext("%s: %s is not this fstype\n"),
758 (void) fprintf(stderr
,
759 gettext("%s: %s is already mounted or %s is busy\n"),
763 (void) fprintf(stderr
, gettext(
764 "%s: %s not a block device\n"), myname
, bs
);
767 (void) fprintf(stderr
, gettext("%s: %s write-protected\n"),
771 (void) fprintf(stderr
, gettext(
772 "%s: The state of %s is not okay\n"
773 "\tand it was attempted to be mounted read/write\n"),
775 (void) printf(gettext(
776 "mount: Please run fsck and try again\n"));
779 (void) fprintf(stderr
, gettext(
780 "%s: Large files may be present on %s,\n"
781 "\tand it was attempted to be mounted nolargefiles\n"),
786 (void) fprintf(stderr
, gettext("%s: Cannot mount %s\n"),