4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * -----------------------------------------------------------------
27 * CFS specific umount command.
30 #pragma ident "%Z%%M% %I% %E% SMI"
33 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
34 * Use is subject to license terms.
49 #include <sys/types.h>
50 #include <sys/param.h>
52 #include <sys/fcntl.h>
53 #include <sys/mount.h>
54 #include <sys/mntent.h>
55 #include <sys/mnttab.h>
56 #include <sys/fs/cachefs_fs.h>
58 #include <sys/utsname.h>
60 #include "../common/subr.h"
61 #include "../common/cachefsd.h"
63 /* forward references */
64 void pr_err(char *fmt
, ...);
65 void usage(char *msgp
);
66 int daemon_unmount(char *mntptp
, int);
73 * Main routine for the cfs umount program.
75 * argc number of command line arguments
76 * argv list of command line arguments
78 * Returns 0 for success or 1 if an error occurs.
83 main(int argc
, char **argv
)
91 char mnt_front
[PATH_MAX
];
92 char mnt_back
[PATH_MAX
];
93 char *p
, mnt_frontns
[PATH_MAX
];
100 (void) setlocale(LC_ALL
, "");
101 #if !defined(TEXT_DOMAIN)
102 #define TEXT_DOMAIN "SYS_TEST"
104 (void) textdomain(TEXT_DOMAIN
);
109 while ((c
= getopt(argc
, argv
, "f")) != EOF
) {
112 flag
|= MS_FORCE
; /* forced unmount is desired */
115 usage("Incorrect number of arguments specified");
120 strcpy(mnt_front
, argv
[2]);
122 strcpy(mnt_front
, argv
[1]);
125 if (strlen(argv
[1]) >= (size_t)PATH_MAX
) {
126 pr_err(gettext("name too long"));
131 * An unmount from autofs may have a
132 * space appended to the path.
133 * Trim it off before attempting to
134 * match the mountpoint in mnttab
136 strcpy(mnt_frontns
, mnt_front
);
137 p
= &mnt_frontns
[strlen(mnt_frontns
) - 1];
141 /* get the mount point and the back file system mount point */
142 finp
= fopen(MNTTAB
, "r");
145 mref
.mnt_mountp
= mnt_frontns
;
146 mref
.mnt_fstype
= "cachefs";
147 ret
= getmntany(finp
, &mget
, &mref
);
149 cachedirp
= (char *)malloc(strlen(mget
.mnt_special
) + 1);
150 strcpy(cachedirp
, mget
.mnt_special
);
152 * AutoClient mounts do not have .cfs_mnt_points string in
153 * them, so strstr would return NULL. So .cfs_unmnt file
156 if ((s
= strstr(cachedirp
, ".cfs_mnt_points")) != NULL
) {
160 cachedirp
[s
-cachedirp
] = '\0';
161 strcat(cachedirp
, CACHEFS_UNMNT_FILE
);
162 if ((ufd
= open(cachedirp
, O_WRONLY
|O_CREAT
|O_TRUNC
,
164 if ((btime
= get_boottime()) != -1)
165 xx
= write(ufd
, &btime
, sizeof (time32_t
));
169 pr_err(gettext(".cfs_unmnt error"));
173 if (mget
.mnt_special
)
174 strcpy(mnt_back
, mget
.mnt_special
);
176 mref
.mnt_special
= mref
.mnt_mountp
;
177 mref
.mnt_mountp
= NULL
;
179 ret
= getmntany(finp
, &mget
, &mref
);
181 strcpy(mnt_front
, mget
.mnt_mountp
);
182 if (mget
.mnt_special
)
183 strcpy(mnt_back
, mget
.mnt_special
);
185 pr_err(gettext("warning: %s not in mnttab"),
192 /* try to get the daemon to unmount this file system for us */
193 xx
= daemon_unmount(mnt_front
, flag
);
197 pr_err(gettext("%s %s"), mnt_front
, strerror(xx
));
201 /* try to unmount the file system directly */
202 if (umount2(mnt_front
, flag
) == -1) {
203 pr_err(gettext("%s %s"), mnt_front
, strerror(errno
));
208 /* if we do not know the name of the back file system mount point */
209 if (mnt_back
[0] == '\0') {
215 * If the back file system was mounted on a directory with a
216 * parent name of BACKMNT_NAME then we assume that we
217 * mounted it and that it is okay to try to umount it.
219 if (strstr(mnt_back
, BACKMNT_NAME
) == NULL
)
222 /* if no back file system mounted */
223 if (strcmp(mnt_back
, "nobackfs") == 0)
227 if ((pid
= fork()) == -1) {
228 pr_err(gettext("could not fork %s"), strerror(errno
));
234 /* invoke the umount command on the back file system */
235 xx
= execl("/sbin/umount", "/sbin/umount", mnt_back
, NULL
);
236 pr_err(gettext("could not exec /sbin/umount"
237 " on back file system %s"), strerror(errno
));
240 /* else if the parent */
242 /* wait for the child to exit */
243 if (wait(&stat_loc
) == -1) {
244 pr_err(gettext("wait failed %s"), strerror(errno
));
248 if (!WIFEXITED(stat_loc
)) {
249 pr_err(gettext("back umount did not exit"));
253 xx
= WEXITSTATUS(stat_loc
);
255 pr_err(gettext("back umount failed"));
260 /* delete the back file system mount point since we created it */
271 * Prints an error message to stderr.
273 * fmt printf style format
274 * ... arguments for fmt
281 pr_err(char *fmt
, ...)
286 (void) fprintf(stderr
, gettext("umount -F cachefs: "));
287 (void) vfprintf(stderr
, fmt
, ap
);
288 (void) fprintf(stderr
, "\n");
297 * Prints a usage message.
299 * An optional additional message to be displayed.
308 pr_err(gettext("%s"), msgp
);
309 fprintf(stderr
, gettext("Usage: umount -F cachefs dir"));
317 * Notifies the cachefsd of an unmount request.
319 * Mount point to unmount.
321 * Returns 0 if the cachefsd unmounted the file system
322 * EIO if should try unmount directly
323 * EBUSY if did not unmount because busy
324 * EAGAIN if umounted but should not unmount nfs mount
331 daemon_unmount(char *mntptp
, int flag
)
334 enum clnt_stat retval
;
339 static struct timeval TIMEOUT
= { 60*60, 0 };
340 static struct timeval create_timeout
= { 5, 0};
341 struct cachefsd_fs_unmounted uargs
;
343 /* get the host name */
346 pr_err(gettext("cannot get host name, errno %d"), errno
);
349 hostp
= info
.nodename
;
350 uargs
.mntpt
= mntptp
;
353 /* creat the connection to the daemon */
354 clnt
= clnt_create_timed(hostp
, CACHEFSDPROG
, CACHEFSDVERS
, "local",
357 pr_err(gettext("cachefsd is not running"));
360 clnt_control(clnt
, CLSET_TIMEOUT
, (char *)&TIMEOUT
);
362 retval
= cachefsd_fs_unmounted_1(&uargs
, &result
, clnt
);
363 if (retval
!= RPC_SUCCESS
) {
364 clnt_perror(clnt
, gettext("cachefsd is not responding"));