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]
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
31 * University Copyright- Copyright (c) 1982, 1986, 1988
32 * The Regents of the University of California
35 * University Acknowledgment- Portions of this document are derived from
36 * software developed by the University of California, Berkeley, and its
40 #pragma ident "%Z%%M% %I% %E% SMI"
54 #include <sys/mnttab.h>
55 #include <sys/mount.h>
56 #include <sys/mntent.h>
58 #include <nfs/nfs_clnt.h>
59 #include <rpcsvc/mount.h>
64 #include <tsol/label.h>
71 static void pr_err(const char *fmt
, ...);
73 static void pr_err(char *fmt
, va_dcl
);
76 static int nfs_unmount(char *, int);
77 static void inform_server(char *, char *, bool_t
);
78 static struct extmnttab
*mnttab_find();
79 extern int __clnt_bindresvport(CLIENT
*);
81 static int is_v4_mount(struct extmnttab
*);
84 static char typename
[64];
87 main(int argc
, char *argv
[])
93 (void) setlocale(LC_ALL
, "");
95 #if !defined(TEXT_DOMAIN)
96 #define TEXT_DOMAIN "SYS_TEST"
98 (void) textdomain(TEXT_DOMAIN
);
100 myname
= strrchr(argv
[0], '/');
101 myname
= myname
? myname
+1 : argv
[0];
102 (void) snprintf(typename
, sizeof (typename
), "nfs %s", myname
);
108 while ((c
= getopt(argc
, argv
, "f")) != EOF
) {
111 umnt_flag
|= MS_FORCE
; /* forced unmount is desired */
118 if (argc
- optind
!= 1) {
123 if (!priv_ineffect(PRIV_SYS_MOUNT
) ||
124 !priv_ineffect(PRIV_NET_PRIVADDR
)) {
125 pr_err(gettext("insufficient privileges\n"));
130 * On a labeled system, a MAC flag may be needed if the mount is
131 * read-down, so attempt to assert it but ignore errors in any case.
133 if (is_system_labeled())
134 (void) setpflags(NET_MAC_AWARE
, 1);
139 return (nfs_unmount(argv
[optind
], umnt_flag
));
143 pr_err(const char *fmt
, ...)
148 (void) fprintf(stderr
, "%s: ", typename
);
149 (void) vfprintf(stderr
, fmt
, ap
);
150 (void) fflush(stderr
);
157 (void) fprintf(stderr
,
158 gettext("Usage: nfs umount [-f] {server:path | dir}\n"));
163 nfs_unmount(char *pathname
, int umnt_flag
)
165 struct extmnttab
*mntp
;
166 bool_t quick
= FALSE
;
169 mntp
= mnttab_find(pathname
);
171 pathname
= mntp
->mnt_mountp
;
175 is_v4
= is_v4_mount(mntp
);
177 /* Forced unmount will almost always be successful */
178 if (umount2(pathname
, umnt_flag
) < 0) {
179 if (errno
== EBUSY
) {
180 pr_err(gettext("%s: is busy\n"), pathname
);
182 pr_err(gettext("%s: not mounted\n"), pathname
);
187 /* All done if it's v4 */
191 /* Inform server quickly in case of forced unmount */
192 if (umnt_flag
& MS_FORCE
)
196 inform_server(mntp
->mnt_special
, mntp
->mnt_mntopts
, quick
);
203 * Find the mnttab entry that corresponds to "name".
204 * We're not sure what the name represents: either
205 * a mountpoint name, or a special name (server:/path).
206 * Return the last entry in the file that matches.
208 static struct extmnttab
*
213 struct extmnttab mnt
;
214 struct extmnttab
*res
= NULL
;
216 fp
= fopen(MNTTAB
, "r");
218 pr_err("%s: %s\n", MNTTAB
, strerror(errno
));
221 while (getextmntent(fp
, &mnt
, sizeof (struct extmnttab
)) == 0) {
222 if (strcmp(mnt
.mnt_mountp
, dirname
) == 0 ||
223 strcmp(mnt
.mnt_special
, dirname
) == 0) {
226 res
= fsdupmnttab(&mnt
);
235 * If quick is TRUE, it will try to inform server quickly
239 inform_server(char *string
, char *opts
, bool_t quick
)
241 struct timeval timeout
;
243 enum clnt_stat rpc_stat
;
244 struct replica
*list
;
247 static struct timeval create_timeout
= {5, 0};
248 static struct timeval
*timep
;
250 list
= parse_replica(string
, &n
);
254 pr_err(gettext("%s is not hostname:path format\n"),
257 pr_err(gettext("no memory\n"));
262 * If mounted with -o public, then no need to contact server
263 * because mount protocol was not used.
266 p
= strstr(opts
, MNTOPT_PUBLIC
);
269 i
= strlen(MNTOPT_PUBLIC
);
271 * Now make sure the match of "public" isn't a substring
274 if (((p
== opts
) || (*(p
-1) == ',')) &&
275 ((p
[i
] == ',') || (p
[i
] == '\0')))
279 for (i
= 0; i
< n
; i
++) {
283 * Skip file systems mounted using WebNFS, because mount
284 * protocol was not used.
286 if (strcmp(list
[i
].host
, "nfs") == 0 && strncmp(list
[i
].path
,
293 * Use 5 sec. timeout if file system is forced unmounted,
294 * otherwise use default timeout to create a client handle.
295 * This would minimize the time to force unmount a file
296 * system reside on a server that is down.
298 timep
= (quick
? &create_timeout
: NULL
);
299 cl
= clnt_create_timed(list
[i
].host
, MOUNTPROG
, vers
,
300 "datagram_n", timep
);
302 * Do not print any error messages in case of forced
307 pr_err("%s:%s %s\n", list
[i
].host
, list
[i
].path
,
309 "server not responding"));
313 * Now it is most likely that the NFS client will be able
314 * to contact the server since rpcbind is running on
315 * the server. There is still a small window in which
316 * server can be unreachable.
319 if (__clnt_bindresvport(cl
) < 0) {
322 "couldn't bind to reserved port\n"));
326 if ((cl
->cl_auth
= authsys_create_default()) == NULL
) {
329 "couldn't create authsys structure\n"));
335 clnt_control(cl
, CLSET_RETRY_TIMEOUT
, (char *)&timeout
);
337 rpc_stat
= clnt_call(cl
, MOUNTPROC_UMNT
, xdr_dirpath
,
338 (char *)&list
[i
].path
, xdr_void
, (char *)NULL
,
340 AUTH_DESTROY(cl
->cl_auth
);
342 if (rpc_stat
== RPC_PROGVERSMISMATCH
&& vers
== MOUNTVERS
) {
344 * The rare case of a v3-only server
349 if (rpc_stat
!= RPC_SUCCESS
)
350 pr_err("%s\n", clnt_sperror(cl
, "unmount"));
353 free_replica(list
, n
);
357 * This function's behavior is taken from nfsstat.
358 * Trying to determine what NFS version was used for the mount.
361 is_v4_mount(struct extmnttab
*mntp
)
363 kstat_ctl_t
*kc
= NULL
; /* libkstat cookie */
365 struct mntinfo_kstat mik
;
370 if ((kc
= kstat_open()) == NULL
)
373 for (ksp
= kc
->kc_chain
; ksp
; ksp
= ksp
->ks_next
) {
374 if (ksp
->ks_type
!= KSTAT_TYPE_RAW
)
376 if (strcmp(ksp
->ks_module
, "nfs") != 0)
378 if (strcmp(ksp
->ks_name
, "mntinfo") != 0)
380 if (mntp
->mnt_minor
!= ksp
->ks_instance
)
383 if (kstat_read(kc
, ksp
, &mik
) == -1)
386 if (mik
.mik_vers
== 4)