1 /* $NetBSD: mount.c,v 1.88 2009/01/11 20:39:34 pooka Exp $ */
4 * Copyright (c) 1980, 1989, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
34 __COPYRIGHT("@(#) Copyright (c) 1980, 1989, 1993, 1994\
35 The Regents of the University of California. All rights reserved.");
40 static char sccsid
[] = "@(#)mount.c 8.25 (Berkeley) 5/8/95";
42 __RCSID("$NetBSD: mount.c,v 1.88 2009/01/11 20:39:34 pooka Exp $");
46 #include <sys/param.h>
47 #include <sys/mount.h>
63 #include <sys/disklabel.h>
64 #include <sys/ioctl.h>
66 #include "pathnames.h"
67 #include "mountprog.h"
69 static int debug
, verbose
;
71 static void catopt(char **, const char *);
73 getfslab(const char *str
);
74 static struct statvfs
*
75 getmntpt(const char *);
76 static int getmntargs(struct statvfs
*, char *, size_t);
77 static int hasopt(const char *, const char *);
78 static void mangle(char *, int *, const char ** volatile *, int *);
79 static int mountfs(const char *, const char *, const char *,
80 int, const char *, const char *, int, char *, size_t);
81 static void prmount(struct statvfs
*);
82 static void usage(void);
85 /* Map from mount otions to printable formats. */
86 static const struct opt
{
94 static char ffs_fstype
[] = "ffs";
97 main(int argc
, char *argv
[])
99 const char *mntfromname
, *mntonname
, **vfslist
, *vfstype
;
101 struct statvfs
*mntbuf
;
105 int all
, ch
, forceall
, i
, init_flags
, mntsize
, rval
;
107 const char *mountopts
, *fstypename
;
108 char canonical_path_buf
[MAXPATHLEN
];
109 char *canonical_path
;
111 /* started as "mount" */
112 all
= forceall
= init_flags
= 0;
115 vfstype
= ffs_fstype
;
116 while ((ch
= getopt(argc
, argv
, "Aadfo:rwt:uv")) != -1)
128 init_flags
|= MNT_FORCE
;
132 catopt(&options
, optarg
);
135 init_flags
|= MNT_RDONLY
;
140 "only one -t option may be specified.");
141 vfslist
= makevfslist(optarg
);
145 init_flags
|= MNT_UPDATE
;
151 init_flags
&= ~MNT_RDONLY
;
161 #define BADTYPE(type) \
162 (strcmp(type, FSTAB_RO) && \
163 strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ))
169 while ((fs
= getfsent()) != NULL
) {
170 if (BADTYPE(fs
->fs_type
))
172 if (checkvfsname(fs
->fs_vfstype
, vfslist
))
174 if (hasopt(fs
->fs_mntops
, "noauto"))
176 if (strcmp(fs
->fs_spec
, "from_mount") == 0) {
177 if ((mntbuf
= getmntpt(fs
->fs_file
)) == NULL
)
179 "unknown file system %s.",
181 mntfromname
= mntbuf
->f_mntfromname
;
183 mntfromname
= fs
->fs_spec
;
184 if (mountfs(fs
->fs_vfstype
, mntfromname
,
185 fs
->fs_file
, init_flags
, options
,
186 fs
->fs_mntops
, !forceall
, NULL
, 0))
190 if ((mntsize
= getmntinfo(&mntbuf
, MNT_NOWAIT
)) == 0)
191 err(1, "getmntinfo");
192 for (i
= 0; i
< mntsize
; i
++) {
193 if (checkvfsname(mntbuf
[i
].f_fstypename
,
202 if (vfslist
!= NULL
) {
208 * Create a canonical version of the device or mount path
209 * passed to us. It's ok for this to fail. It's also ok
210 * for the result to be exactly the same as the original.
212 canonical_path
= realpath(*argv
, canonical_path_buf
);
214 if (init_flags
& MNT_UPDATE
) {
216 * Try looking up the canonical path first,
217 * then try exactly what the user entered.
219 if ((canonical_path
== NULL
||
220 (mntbuf
= getmntpt(canonical_path
)) == NULL
) &&
221 (mntbuf
= getmntpt(*argv
)) == NULL
225 "unknown special file or file system %s.",
228 mntfromname
= mntbuf
->f_mntfromname
;
229 if ((fs
= getfsfile(mntbuf
->f_mntonname
)) != NULL
) {
230 if (strcmp(fs
->fs_spec
, "from_mount") != 0)
231 mntfromname
= fs
->fs_spec
;
232 /* ignore the fstab file options. */
233 fs
->fs_mntops
= NULL
;
235 mntonname
= mntbuf
->f_mntonname
;
236 fstypename
= mntbuf
->f_fstypename
;
240 * Try looking up the canonical path first,
241 * then try exactly what the user entered.
243 if (canonical_path
== NULL
||
244 ((fs
= getfsfile(canonical_path
)) == NULL
&&
245 (fs
= getfsspec(canonical_path
)) == NULL
))
247 if ((fs
= getfsfile(*argv
)) == NULL
&&
248 (fs
= getfsspec(*argv
)) == NULL
)
251 "%s: unknown special file or file system.",
255 if (BADTYPE(fs
->fs_type
))
256 errx(1, "%s has unknown file system type.",
258 if (strcmp(fs
->fs_spec
, "from_mount") == 0) {
259 if ((canonical_path
== NULL
||
260 (mntbuf
= getmntpt(canonical_path
)) == NULL
) &&
261 (mntbuf
= getmntpt(*argv
)) == NULL
265 "unknown special file or file system %s.",
268 mntfromname
= mntbuf
->f_mntfromname
;
270 mntfromname
= fs
->fs_spec
;
271 mntonname
= fs
->fs_file
;
272 fstypename
= fs
->fs_vfstype
;
273 mountopts
= fs
->fs_mntops
;
275 rval
= mountfs(fstypename
, mntfromname
,
276 mntonname
, init_flags
, options
, mountopts
, 0, NULL
, 0);
280 * If -t flag has not been specified, and spec contains either
281 * a ':' or a '@' then assume that an NFS filesystem is being
284 if (vfslist
== NULL
) {
285 if (strpbrk(argv
[0], ":@") != NULL
) {
286 fprintf(stderr
, "WARNING: autoselecting nfs "
287 "based on : or @ in the device name is "
289 "WARNING: This behaviour will be removed "
290 "in a future release\n");
293 vfstype
= getfslab(argv
[0]);
295 vfstype
= ffs_fstype
;
298 rval
= mountfs(vfstype
,
299 argv
[0], argv
[1], init_flags
, options
, NULL
, 0, NULL
, 0);
306 #if 0 /* disabled because it interferes the service. */
308 * If the mount was successfully, and done by root, tell mountd the
309 * good news. Pid checks are probably unnecessary, but don't hurt.
311 if (rval
== 0 && getuid() == 0 &&
312 (mountdfp
= fopen(_PATH_MOUNTDPID
, "r")) != NULL
) {
315 if (fscanf(mountdfp
, "%d", &pid
) == 1 &&
316 pid
> 0 && kill(pid
, SIGHUP
) == -1 && errno
!= ESRCH
)
317 err(1, "signal mountd");
318 (void)fclose(mountdfp
);
327 hasopt(const char *mntopts
, const char *option
)
332 if (option
[0] == 'n' && option
[1] == 'o') {
337 optbuf
= strdup(mntopts
);
339 for (opt
= optbuf
; (opt
= strtok(opt
, ",")) != NULL
; opt
= NULL
) {
340 if (opt
[0] == 'n' && opt
[1] == 'o') {
341 if (!strcasecmp(opt
+ 2, option
))
343 } else if (!strcasecmp(opt
, option
))
351 mountfs(const char *vfstype
, const char *spec
, const char *name
,
352 int flags
, const char *options
, const char *mntopts
,
353 int skipmounted
, char *buf
, size_t buflen
)
355 /* List of directories containing mount_xxx subcommands. */
356 static const char *edirs
[] = {
364 const char ** volatile argv
, **edir
;
365 struct statvfs
*sfp
, sf
;
368 int argc
, numfs
, i
, status
, maxargc
;
369 char *optbuf
, execname
[MAXPATHLEN
+ 1], execbase
[MAXPATHLEN
],
371 volatile int getargs
;
373 if (realpath(name
, mntpath
) == NULL
) {
374 warn("realpath %s", name
);
382 catopt(&optbuf
, mntopts
);
385 catopt(&optbuf
, options
);
386 getargs
= strstr(options
, "getargs") != NULL
;
390 if (!mntopts
&& !options
)
391 catopt(&optbuf
, "rw");
393 if (getargs
== 0 && strcmp(name
, "/") == 0)
395 else if (skipmounted
) {
396 if ((numfs
= getmntinfo(&sfp
, MNT_WAIT
)) == 0) {
400 for(i
= 0; i
< numfs
; i
++) {
402 * XXX can't check f_mntfromname,
403 * thanks to mfs, union, etc.
405 if (strncmp(name
, sfp
[i
].f_mntonname
, MNAMELEN
) == 0 &&
406 strncmp(vfstype
, sfp
[i
].f_fstypename
,
407 sizeof(sfp
[i
].f_fstypename
)) == 0) {
409 (void)printf("%s on %s type %.*s: "
411 sfp
[i
].f_mntfromname
,
413 (int)sizeof(sfp
[i
].f_fstypename
),
420 if (flags
& MNT_FORCE
)
421 catopt(&optbuf
, "force");
422 if (flags
& MNT_RDONLY
)
423 catopt(&optbuf
, "ro");
425 if (flags
& MNT_UPDATE
) {
426 catopt(&optbuf
, "update");
427 /* Figure out the fstype only if we defaulted to ffs */
428 if (vfstype
== ffs_fstype
&& statvfs(name
, &sf
) != -1)
429 vfstype
= sf
.f_fstypename
;
433 argv
= malloc(sizeof(char *) * maxargc
);
437 if (hasopt(optbuf
, "rump"))
438 (void)snprintf(execbase
, sizeof(execbase
), "rump_%s", vfstype
);
440 (void)snprintf(execbase
, sizeof(execbase
), "mount_%s", vfstype
);
442 argv
[argc
++] = execbase
;
444 mangle(optbuf
, &argc
, &argv
, &maxargc
);
449 if ((verbose
&& buf
== NULL
) || debug
) {
450 (void)printf("exec:");
451 for (i
= 0; i
< argc
; i
++)
452 (void)printf(" %s", argv
[i
]);
458 warn("Cannot create pipe");
461 switch (pid
= vfork()) {
462 case -1: /* Error. */
475 (void)close(STDOUT_FILENO
);
476 if (dup2(pfd
[1], STDOUT_FILENO
) == -1)
477 warn("Cannot open fd to mount program");
480 /* Go find an executable. */
483 (void)snprintf(execname
,
484 sizeof(execname
), "%s/%s", *edir
, execbase
);
485 (void)execv(execname
, __UNCONST(argv
));
487 warn("exec %s for %s", execname
, name
);
488 } while (*++edir
!= NULL
);
491 warnx("%s not found for %s", execbase
, name
);
495 default: /* Parent. */
500 if (buf
|| getargs
) {
501 char tbuf
[1024], *ptr
;
506 buflen
= sizeof(tbuf
) - 1;
512 (void)signal(SIGPIPE
, SIG_IGN
);
513 while ((nread
= read(pfd
[0], ptr
, buflen
)) > 0) {
519 while (read(pfd
[0], &nread
, sizeof(nread
)) > 0)
523 (void)fprintf(stdout
, "%s", tbuf
);
526 if (waitpid(pid
, &status
, 0) < 0) {
531 if (WIFEXITED(status
)) {
532 if (WEXITSTATUS(status
) != 0)
533 return (WEXITSTATUS(status
));
534 } else if (WIFSIGNALED(status
)) {
535 warnx("%s: %s", name
, strsignal(WTERMSIG(status
)));
541 if (statvfs(name
, &sf
) < 0) {
542 warn("statvfs %s", name
);
555 prmount(struct statvfs
*sfp
)
562 (void)printf("%s on %s type %.*s", sfp
->f_mntfromname
,
563 sfp
->f_mntonname
, (int)sizeof(sfp
->f_fstypename
),
566 flags
= sfp
->f_flag
& MNT_VISFLAGMASK
;
567 for (f
= 0, o
= optnames
; flags
&& o
<
568 &optnames
[sizeof(optnames
)/sizeof(optnames
[0])]; o
++)
569 if (flags
& o
->o_opt
) {
570 if (!o
->o_silent
|| verbose
)
571 (void)printf("%s%s", !f
++ ? " (" : ", ",
576 (void)printf("%sunknown flag%s %#x", !f
++ ? " (" : ", ",
577 flags
& (flags
- 1) ? "s" : "", flags
);
579 (void)printf("%smounted by ", !f
++ ? " (" : ", ");
580 if ((pw
= getpwuid(sfp
->f_owner
)) != NULL
)
581 (void)printf("%s", pw
->pw_name
);
583 (void)printf("%d", sfp
->f_owner
);
586 (void)printf("%sfsid: 0x%x/0x%x",
587 !f
++ ? " (" /* ) */: ", ",
588 sfp
->f_fsidx
.__fsid_val
[0], sfp
->f_fsidx
.__fsid_val
[1]);
591 (void)printf("%s", !f
++ ? " (" : ", ");
592 (void)printf("reads: sync %" PRIu64
" async %" PRIu64
"",
593 sfp
->f_syncreads
, sfp
->f_asyncreads
);
594 (void)printf(", writes: sync %" PRIu64
" async %" PRIu64
"",
595 sfp
->f_syncwrites
, sfp
->f_asyncwrites
);
599 if (getmntargs(sfp
, buf
, sizeof(buf
)))
600 printf(", [%s: %s]", sfp
->f_fstypename
, buf
);
604 (void)printf("%s", f
? ")\n" : "\n");
608 getmntargs(struct statvfs
*sfs
, char *buf
, size_t buflen
)
611 if (mountfs(sfs
->f_fstypename
, sfs
->f_mntfromname
, sfs
->f_mntonname
, 0,
612 "getargs", NULL
, 0, buf
, buflen
))
617 if ((buf
= strchr(buf
, '\n')) != NULL
)
623 static struct statvfs
*
624 getmntpt(const char *name
)
626 struct statvfs
*mntbuf
;
629 mntsize
= getmntinfo(&mntbuf
, MNT_NOWAIT
);
630 for (i
= 0; i
< mntsize
; i
++)
631 if (strcmp(mntbuf
[i
].f_mntfromname
, name
) == 0 ||
632 strcmp(mntbuf
[i
].f_mntonname
, name
) == 0)
638 catopt(char **sp
, const char *o
)
644 if (asprintf(&n
, "%s,%s", s
, o
) < 0)
654 mangle(char *options
, int *argcp
, const char ** volatile *argvp
, int *maxargcp
)
658 const char **argv
, **nargv
;
664 for (s
= options
; (p
= strsep(&s
, ",")) != NULL
;) {
665 /* Always leave space for one more argument and the NULL. */
666 if (argc
>= maxargc
- 4) {
667 nargv
= realloc(argv
, (maxargc
<< 1) * sizeof(char *));
681 } else if (strcmp(p
, "rw") != 0) {
693 /* Deduce the filesystem type from the disk label. */
695 getfslab(const char *str
)
697 static struct dkwedge_info dkw
;
703 char buf
[MAXPATHLEN
+ 1];
706 if ((fd
= open(str
, O_RDONLY
)) == -1) {
708 * Iff we get EBUSY try the raw device. Since mount always uses
709 * the block device we know we are never passed a raw device.
712 err(1, "cannot open `%s'", str
);
713 strlcpy(buf
, str
, MAXPATHLEN
);
714 if ((sp
= strrchr(buf
, '/')) != NULL
)
718 for (ep
= sp
+ strlen(sp
) + 1; ep
> sp
; ep
--)
722 /* Silently fail here - mount call can display error */
723 if ((fd
= open(buf
, O_RDONLY
)) == -1)
727 /* Check to see if this is a wedge. */
728 if (ioctl(fd
, DIOCGWEDGEINFO
, &dkw
) == 0) {
729 /* Yup, this is easy. */
731 return (dkw
.dkw_ptype
);
734 if (ioctl(fd
, DIOCGDINFO
, &dl
) == -1) {
741 part
= str
[strlen(str
) - 1] - 'a';
743 if (part
< 0 || part
>= dl
.d_npartitions
)
746 /* Return NULL for unknown types - caller can fall back to ffs */
747 if ((fstype
= dl
.d_partitions
[part
].p_fstype
) >= FSMAXMOUNTNAMES
)
750 vfstype
= mountnames
[fstype
];
759 (void)fprintf(stderr
,
760 "usage: mount %s\n mount %s\n mount %s\n",
761 "[-Aadfruvw] [-t type]",
762 "[-dfruvw] special | node",
763 "[-dfruvw] [-o options] [-t type] special node");