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 */
89 #define NAME_MAX 64 /* sizeof "fstype myname" */
91 static int checkislog(char *);
92 static void disable_logging(char *, char *);
93 static int eatmntopt(struct mnttab
*, char *);
94 static void enable_logging(char *, char *);
95 static void fixopts(struct mnttab
*, char *);
96 static void mountfs(struct mnttab
*);
97 static void replace_opts(char *, int, char *, char *);
98 static int replace_opts_dflt(char *, int, const char *, const char *);
99 static void rmopt(struct mnttab
*, char *);
100 static void rpterr(char *, char *);
101 static void usage(void);
103 static char fstype
[] = MNTTYPE_UFS
;
104 static char opts
[MAX_MNTOPT_STR
];
105 static char typename
[NAME_MAX
], *myname
;
106 static char *fop_subopts
[] = { MNTOPT_ONERROR
, NULL
};
108 #define ONERROR (0) /* index within fop_subopts */
110 static struct fop_subopt
{
113 } fop_subopt_list
[] = {
114 { UFSMNT_ONERROR_PANIC_STR
, UFSMNT_ONERROR_PANIC
},
115 { UFSMNT_ONERROR_LOCK_STR
, UFSMNT_ONERROR_LOCK
},
116 { UFSMNT_ONERROR_UMOUNT_STR
, UFSMNT_ONERROR_UMOUNT
},
117 { NULL
, UFSMNT_ONERROR_DEFAULT
}
122 * Check if the specified filesystem is already mounted.
125 in_mnttab(char *mountp
)
129 struct mnttab mntent
;
131 if ((file
= fopen(MNTTAB
, "r")) == NULL
)
133 while (getmntent(file
, &mntent
) == 0) {
134 if (mntent
.mnt_mountp
!= NULL
&&
135 strcmp(mntent
.mnt_mountp
, mountp
) == 0 &&
136 mntent
.mnt_fstype
!= NULL
&&
137 strcmp(mntent
.mnt_fstype
, MNTTYPE_UFS
) == 0) {
150 findopt(char *mntopt
, char *opt
)
152 int nc
, optlen
= strlen(opt
);
155 nc
= strcspn(mntopt
, ", =");
156 if (strncmp(mntopt
, opt
, nc
) == 0)
160 mntopt
+= strspn(mntopt
, ", =");
166 main(int argc
, char *argv
[])
171 (void) setlocale(LC_ALL
, "");
172 #if !defined(TEXT_DOMAIN)
173 #define TEXT_DOMAIN "SYS_TEST"
175 (void) textdomain(TEXT_DOMAIN
);
177 myname
= strrchr(argv
[0], '/');
182 (void) snprintf(typename
, sizeof (typename
), "%s %s", fstype
, myname
);
190 while ((c
= getopt(argc
, argv
, "gmo:pqrVO")) != EOF
) {
198 if (strlcpy(opts
, optarg
, sizeof (opts
)) >=
200 (void) fprintf(stderr
, gettext("option string "
201 "argument too long\n"));
226 if ((argc
- optind
) != 2)
229 mnt
.mnt_special
= argv
[optind
];
230 mnt
.mnt_mountp
= argv
[optind
+1];
231 mnt
.mnt_fstype
= fstype
;
234 * Process options. The resulting options string overwrites the
237 * XXX: This code doesn't do a good job of resolving options that are
238 * specified multiple times or that are given in conflicting
239 * forms (e.g., both "largefiles" and "nolargefiles"). It also
240 * doesn't produce well defined behavior for options that may
241 * also be specified as flags (e.g, "-r" and "ro"/"rw") when both
244 * The proper way to deal with such conflicts is to start with
245 * the default value (i.e., the one if no flag or option is
246 * specified), override it with the last mentioned option pair
247 * in the -o option string, and finally, override that with
248 * the flag value. This allows "mount -r" command to mount a
249 * file system read only that is listed rw in /etc/vfstab.
251 mnt
.mnt_mntopts
= opts
;
252 if (findopt(mnt
.mnt_mntopts
, "m"))
254 if ((gflg
|| findopt(mnt
.mnt_mntopts
, MNTOPT_GLOBAL
)) &&
255 findopt(mnt
.mnt_mntopts
, MNTOPT_NBMAND
)) {
256 (void) fprintf(stderr
, gettext("NBMAND option not supported on"
257 " global filesystem\n"));
261 replace_opts(opts
, ro
, MNTOPT_RO
, MNTOPT_RW
);
262 replace_opts(opts
, largefiles
, MNTOPT_NOLARGEFILES
, MNTOPT_LARGEFILES
);
263 gflg
= replace_opts_dflt(opts
, gflg
, MNTOPT_GLOBAL
, MNTOPT_NOGLOBAL
);
265 if (findopt(mnt
.mnt_mntopts
, MNTOPT_RQ
)) {
266 rmopt(&mnt
, MNTOPT_RQ
);
267 replace_opts(opts
, 1, MNTOPT_QUOTA
, MNTOPT_NOQUOTA
);
275 reportlogerror(int ret
, char *mp
, char *special
, char *cmd
, fiolog_t
*flp
)
278 if ((ret
!= -1) && (flp
->error
== FIOLOG_ENONE
))
281 /* logging was not enabled/disabled */
282 if (ret
== -1 || flp
->error
!= FIOLOG_ENONE
)
283 (void) fprintf(stderr
, gettext("Could not %s logging"
284 " for %s on %s.\n"), cmd
, mp
, special
);
286 /* ioctl returned error */
291 switch (flp
->error
) {
293 if (flp
->nbytes_requested
&&
294 (flp
->nbytes_requested
!= flp
->nbytes_actual
)) {
295 (void) fprintf(stderr
, gettext("The log has been"
296 " resized from %d bytes to %d bytes.\n"),
297 flp
->nbytes_requested
,
302 (void) fprintf(stderr
, gettext("Solaris Volume Manager logging"
303 " is already enabled.\n"));
304 (void) fprintf(stderr
, gettext("Please see the"
305 " commands metadetach(1M)"
306 " or metaclear(1M).\n"));
309 (void) fprintf(stderr
, gettext("File system is mounted read "
311 (void) fprintf(stderr
, gettext("Please see the remount "
312 "option described in mount_ufs(1M).\n"));
315 (void) fprintf(stderr
, gettext("File system is locked.\n"));
316 (void) fprintf(stderr
, gettext("Please see the -u option "
317 "described in lockfs(1M).\n"));
320 (void) fprintf(stderr
, gettext("The file system could not be"
321 " write locked.\n"));
322 (void) fprintf(stderr
, gettext("Please see the -w option "
323 "described in lockfs(1M).\n"));
326 (void) fprintf(stderr
, gettext("The file system may not be"
328 (void) fprintf(stderr
, gettext("Please see the -n option"
329 " for fsck(1M).\n"));
331 case FIOLOG_ENOULOCK
:
332 (void) fprintf(stderr
, gettext("The file system could not be"
334 (void) fprintf(stderr
, gettext("Please see the -u option "
335 "described in lockfs(1M).\n"));
338 (void) fprintf(stderr
, gettext("Unknown internal error"
339 " %d.\n"), flp
->error
);
350 fd
= open(mp
, O_RDONLY
);
352 (void) ioctl(fd
, _FIOISLOG
, &islog
);
358 enable_logging(char *mp
, char *special
)
363 fd
= open(mp
, O_RDONLY
);
368 fl
.nbytes_requested
= 0;
369 fl
.nbytes_actual
= 0;
370 fl
.error
= FIOLOG_ENONE
;
371 ret
= ioctl(fd
, _FIOLOGENABLE
, &fl
);
376 /* is logging enabled? */
377 islog
= checkislog(mp
);
379 /* report errors, if any */
380 if (ret
== -1 || !islog
)
381 reportlogerror(ret
, mp
, special
, "enable", &fl
);
385 disable_logging(char *mp
, char *special
)
390 fd
= open(mp
, O_RDONLY
);
395 fl
.error
= FIOLOG_ENONE
;
396 ret
= ioctl(fd
, _FIOLOGDISABLE
, &fl
);
401 /* is logging enabled? */
402 islog
= checkislog(mp
);
404 /* report errors, if any */
405 if (ret
== -1 || islog
)
406 reportlogerror(ret
, mp
, special
, "disable", &fl
);
411 * attempt to mount file system, return errno or 0
414 mountfs(struct mnttab
*mnt
)
416 char opt
[MAX_MNTOPT_STR
];
417 char opt2
[MAX_MNTOPT_STR
];
419 int flags
= MS_OPTIONSTR
;
420 struct ufs_args args
;
421 int need_separator
= 0;
422 int mount_attempts
= 5;
424 (void) bzero((char *)&args
, sizeof (args
));
425 (void) strcpy(opts
, mnt
->mnt_mntopts
);
428 flags
|= Oflg
? MS_OVERLAY
: 0;
429 flags
|= eatmntopt(mnt
, MNTOPT_RO
) ? MS_RDONLY
: 0;
430 flags
|= eatmntopt(mnt
, MNTOPT_REMOUNT
) ? MS_REMOUNT
: 0;
431 flags
|= eatmntopt(mnt
, MNTOPT_GLOBAL
) ? MS_GLOBAL
: 0;
433 if (eatmntopt(mnt
, MNTOPT_NOINTR
))
434 args
.flags
|= UFSMNT_NOINTR
;
435 if (eatmntopt(mnt
, MNTOPT_INTR
))
436 args
.flags
&= ~UFSMNT_NOINTR
;
437 if (eatmntopt(mnt
, MNTOPT_SYNCDIR
))
438 args
.flags
|= UFSMNT_SYNCDIR
;
439 if (eatmntopt(mnt
, MNTOPT_FORCEDIRECTIO
)) {
440 args
.flags
|= UFSMNT_FORCEDIRECTIO
;
441 args
.flags
&= ~UFSMNT_NOFORCEDIRECTIO
;
443 if (eatmntopt(mnt
, MNTOPT_NOFORCEDIRECTIO
)) {
444 args
.flags
|= UFSMNT_NOFORCEDIRECTIO
;
445 args
.flags
&= ~UFSMNT_FORCEDIRECTIO
;
447 if (eatmntopt(mnt
, MNTOPT_NOSETSEC
))
448 args
.flags
|= UFSMNT_NOSETSEC
;
449 if (eatmntopt(mnt
, MNTOPT_LARGEFILES
))
450 args
.flags
|= UFSMNT_LARGEFILES
;
451 if (eatmntopt(mnt
, MNTOPT_NOLARGEFILES
))
452 args
.flags
&= ~UFSMNT_LARGEFILES
;
453 args
.flags
|= UFSMNT_LOGGING
; /* default is logging */
454 (void) eatmntopt(mnt
, MNTOPT_LOGGING
);
455 if (eatmntopt(mnt
, MNTOPT_NOLOGGING
))
456 args
.flags
&= ~UFSMNT_LOGGING
;
457 if (eatmntopt(mnt
, MNTOPT_NOATIME
))
458 args
.flags
|= UFSMNT_NOATIME
;
459 if (eatmntopt(mnt
, MNTOPT_DFRATIME
))
460 args
.flags
&= ~UFSMNT_NODFRATIME
;
461 if (eatmntopt(mnt
, MNTOPT_NODFRATIME
))
462 args
.flags
|= UFSMNT_NODFRATIME
;
464 while (*opts
!= '\0') {
467 switch (getsubopt(&opts
, fop_subopts
, &argval
)) {
470 struct fop_subopt
*s
;
473 for (s
= fop_subopt_list
;
476 if (strcmp(argval
, s
->str
) == 0) {
477 args
.flags
|= s
->flag
;
486 (void) strcat(opt2
, ",");
487 (void) strcat(opt2
, MNTOPT_ONERROR
);
488 (void) strcat(opt2
, "=");
489 (void) strcat(opt2
, argval
);
493 args
.flags
|= UFSMNT_ONERROR_DEFAULT
;
501 (void) strcat(opt2
, ",");
502 (void) strcat(opt2
, argval
);
511 (void) strcpy(opt
, opt2
);
513 if ((args
.flags
& UFSMNT_ONERROR_FLGMASK
) == 0)
514 args
.flags
|= UFSMNT_ONERROR_DEFAULT
;
516 (void) signal(SIGHUP
, SIG_IGN
);
517 (void) signal(SIGQUIT
, SIG_IGN
);
518 (void) signal(SIGINT
, SIG_IGN
);
521 flags
|= MS_DATA
| MS_OPTIONSTR
;
523 flags
|= MS_NOMNTTAB
;
524 if (flags
& MS_REMOUNT
) {
525 replace_opts(mnt
->mnt_mntopts
, 1, MNTOPT_RW
, MNTOPT_RO
);
530 * For global filesystems we want to pass in logging option
531 * so that it shows up in the mnttab of all nodes. We add
532 * logging option if its not specified.
534 if (gflg
|| findopt(mnt
->mnt_mntopts
, MNTOPT_GLOBAL
)) {
535 if (!(flags
& MS_RDONLY
)) {
536 if (mnt
->mnt_mntopts
!= '\0')
537 (void) strcat(mnt
->mnt_mntopts
, ",");
538 (void) strcat(mnt
->mnt_mntopts
, MNTOPT_LOGGING
);
539 args
.flags
|= UFSMNT_LOGGING
;
542 * Turn off logging for read only global mounts.
543 * It was set to logging as default above.
545 if (mnt
->mnt_mntopts
!= '\0')
546 (void) strcat(mnt
->mnt_mntopts
, ",");
547 (void) strcat(mnt
->mnt_mntopts
, MNTOPT_NOLOGGING
);
548 args
.flags
&= ~UFSMNT_LOGGING
;
552 again
: if (mount(mnt
->mnt_special
, mnt
->mnt_mountp
, flags
, fstype
,
553 &args
, sizeof (args
), mnt
->mnt_mntopts
, MAX_MNTOPT_STR
) != 0) {
554 if (errno
== EBUSY
&& !(flags
& MS_OVERLAY
)) {
556 * Because of bug 6176743, any attempt to mount any
557 * filesystem could fail for reasons described in that
558 * bug. We're trying to detect that situation here by
559 * checking that the filesystem we're mounting is not
560 * in /etc/mnttab yet. When that bug is fixed, this
561 * code can be removed.
563 if (!in_mnttab(mnt
->mnt_mountp
) &&
564 mount_attempts
-- > 0) {
565 (void) poll(NULL
, 0, 50);
569 rpterr(mnt
->mnt_special
, mnt
->mnt_mountp
);
573 if (!(flags
& MS_RDONLY
)) {
574 if (args
.flags
& UFSMNT_LOGGING
)
575 enable_logging(mnt
->mnt_mountp
, mnt
->mnt_special
);
577 disable_logging(mnt
->mnt_mountp
, mnt
->mnt_special
);
581 cmp_requested_to_actual_options(opts
, mnt
->mnt_mntopts
,
582 mnt
->mnt_special
, mnt
->mnt_mountp
);
585 if (checkislog(mnt
->mnt_mountp
)) {
586 /* update mnttab file if necessary */
589 struct mnttagdesc mtdesc
;
592 if (stat64(mnt
->mnt_mountp
, &statb
) != 0)
595 mtdesc
.mtd_major
= major(statb
.st_dev
);
596 mtdesc
.mtd_minor
= minor(statb
.st_dev
);
597 mtdesc
.mtd_mntpt
= mnt
->mnt_mountp
;
598 mtdesc
.mtd_tag
= MNTOPT_LOGGING
;
599 if ((fd
= open(MNTTAB
, O_RDONLY
, 0)) < 0)
601 if (ioctl(fd
, MNTIOC_SETTAG
, &mtdesc
) != 0) {
612 * same as findopt but remove the option from the option string and return
616 eatmntopt(struct mnttab
*mnt
, char *opt
)
620 has
= (findopt(mnt
->mnt_mntopts
, opt
) != NULL
);
626 * remove an option string from the option list
629 rmopt(struct mnttab
*mnt
, char *opt
)
634 while (optstart
= findopt(mnt
->mnt_mntopts
, opt
)) {
636 *str
!= ',' && *str
!= '\0' && *str
!= ' ';
641 } else if (optstart
!= mnt
->mnt_mntopts
) {
644 while (*optstart
++ = *str
++)
650 * mnt->mnt_ops has un-eaten opts, opts is the original opts list.
651 * Set mnt->mnt_opts to the original, the kernel will then remove
652 * the ones it cannot deal with.
653 * Set "opts" to the the original options for later comparison in
654 * cmp_....(). But strip the options which aren't returned by
655 * the kernel: "noglobal", "global" and "quota".
656 * And strip the options which aren't set through mount: "logging",
657 * "nologging" from those passed to mount(2).
660 fixopts(struct mnttab
*mnt
, char *opts
)
664 omnt
.mnt_mntopts
= opts
;
667 * Options not passed to the kernel and possibly not returned;
668 * these are dealt with using ioctl; and the ioctl may fail.
670 rmopt(&omnt
, MNTOPT_LOGGING
);
671 rmopt(&omnt
, MNTOPT_NOLOGGING
);
674 * Set the options for ``/etc/mnttab'' to be the original
675 * options from main(); except for the option "f" and "remount".
677 (void) strlcpy(mnt
->mnt_mntopts
, opts
, MAX_MNTOPT_STR
);
679 rmopt(mnt
, MNTOPT_REMOUNT
);
681 rmopt(&omnt
, MNTOPT_GLOBAL
);
682 rmopt(&omnt
, MNTOPT_NOGLOBAL
);
683 rmopt(&omnt
, MNTOPT_QUOTA
);
689 (void) fprintf(stdout
, gettext(
691 "mount [-F ufs] [generic options] [-o suboptions] {special | mount_point}\n"));
692 (void) fprintf(stdout
, gettext(
693 "\tsuboptions are: \n"
694 "\t ro,rw,nosuid,remount,f,m,\n"
695 "\t global,noglobal,\n"
696 "\t largefiles,nolargefiles,\n"
697 "\t forcedirectio,noforcedirectio\n"
698 "\t logging,nologging,\n"
699 "\t nbmand,nonbmand,\n"
700 "\t onerror[={panic | lock | umount}]\n"));
706 * Returns the next option in the option string.
714 while (*cp
&& isspace(*cp
))
717 while (*cp
&& *cp
!= ',')
719 /* strip empty options */
729 * "trueopt" and "falseopt" are two settings of a Boolean option.
730 * If "flag" is true, forcibly set the option to the "true" setting; otherwise,
731 * if the option isn't present, set it to the false setting.
734 replace_opts(char *options
, int flag
, char *trueopt
, char *falseopt
)
739 char tmptopts
[MNTMAXSTR
];
741 (void) strcpy(tmptopts
, options
);
743 (void) strcpy(options
, "");
746 for (f
= getnextopt(&tmpoptsp
); *f
; f
= getnextopt(&tmpoptsp
)) {
747 if (options
[0] != '\0')
748 (void) strcat(options
, ",");
749 if (strcmp(f
, trueopt
) == 0) {
750 (void) strcat(options
, f
);
752 } else if (strcmp(f
, falseopt
) == 0) {
754 (void) strcat(options
, trueopt
);
756 (void) strcat(options
, f
);
759 (void) strcat(options
, f
);
762 if (options
[0] != '\0')
763 (void) strcat(options
, ",");
764 (void) strcat(options
, flag
? trueopt
: falseopt
);
769 * "trueopt" and "falseopt" are two settings of a Boolean option and "dflt" is
770 * a default value for the option. Rewrite the contents of options to include
771 * only the last mentioned occurrence of trueopt and falseopt. If neither is
772 * mentioned, append one or the other to options, according to the value of
773 * dflt. Return the resulting value of the option in boolean form.
775 * Note that the routine is implemented to have the resulting occurrence of
776 * trueopt or falseopt appear at the end of the resulting option string.
778 * N.B. This routine should take the place of replace_opts, but there are
779 * probably some compatibility issues to resolve before doing so. It
780 * should certainly be used to handle new options that don't have
781 * compatibility issues.
788 const char *falseopt
)
793 char tmptopts
[MNTMAXSTR
];
796 * Transfer the contents of options to tmptopts, in anticipation of
797 * copying a subset of the contents back to options.
799 (void) strcpy(tmptopts
, options
);
801 (void) strcpy(options
, "");
804 * Loop over each option value, copying non-matching values back into
805 * options and updating the last seen occurrence of trueopt or
809 for (f
= getnextopt(&tmpoptsp
); *f
; f
= getnextopt(&tmpoptsp
)) {
810 /* Check for both forms of the option of interest. */
811 if (strcmp(f
, trueopt
) == 0) {
813 } else if (strcmp(f
, falseopt
) == 0) {
816 /* Not what we're looking for; transcribe. */
817 if (options
[0] != '\0')
818 (void) strcat(options
, ",");
819 (void) strcat(options
, f
);
824 * Transcribe the correct form of the option of interest, using the
825 * default value if it wasn't overwritten above.
827 if (options
[0] != '\0')
828 (void) strcat(options
, ",");
829 (void) strcat(options
, last
? trueopt
: falseopt
);
835 rpterr(char *bs
, char *mp
)
839 (void) fprintf(stderr
, gettext("%s: Insufficient privileges\n"),
843 (void) fprintf(stderr
, gettext("%s: %s no such device\n"),
847 (void) fprintf(stderr
,
849 "%s: %s not a directory\n\tor a component of %s is not a directory\n"),
853 (void) fprintf(stderr
, gettext(
854 "%s: %s or %s, no such file or directory\n"),
858 (void) fprintf(stderr
, gettext("%s: %s is not this fstype\n"),
862 (void) fprintf(stderr
,
863 gettext("%s: %s is already mounted or %s is busy\n"),
867 (void) fprintf(stderr
, gettext(
868 "%s: %s not a block device\n"), myname
, bs
);
871 (void) fprintf(stderr
, gettext("%s: %s write-protected\n"),
875 (void) fprintf(stderr
, gettext(
876 "%s: The state of %s is not okay\n"
877 "\tand it was attempted to be mounted read/write\n"),
879 (void) printf(gettext(
880 "mount: Please run fsck and try again\n"));
883 (void) fprintf(stderr
, gettext(
884 "%s: Large files may be present on %s,\n"
885 "\tand it was attempted to be mounted nolargefiles\n"),
890 (void) fprintf(stderr
, gettext("%s: Cannot mount %s\n"),