1/*	$NetBSD: umount_default.c,v 1.1.1.3 2015/01/17 16:34:16 christos Exp $	*/
2
3/*
4 * Copyright (c) 1997-2014 Erez Zadok
5 * Copyright (c) 1990 Jan-Simon Pendry
6 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
7 * Copyright (c) 1990 The Regents of the University of California.
8 * All rights reserved.
9 *
10 * This code is derived from software contributed to Berkeley by
11 * Jan-Simon Pendry at Imperial College, London.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 *    notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 *    notice, this list of conditions and the following disclaimer in the
20 *    documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of the University nor the names of its contributors
22 *    may be used to endorse or promote products derived from this software
23 *    without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 *
38 * File: am-utils/conf/umount/umount_default.c
39 *
40 */
41
42/*
43 * Default method of unmounting filesystems.
44 */
45
46#ifdef HAVE_CONFIG_H
47# include <config.h>
48#endif /* HAVE_CONFIG_H */
49#include <am_defs.h>
50#include <amu.h>
51
52
53int
54umount_fs(char *mntdir, const char *mnttabname, u_int unmount_flags)
55{
56  mntlist *mlist, *mp, *mp_save = NULL;
57  int error = 0;
58
59  mp = mlist = read_mtab(mntdir, mnttabname);
60
61  /*
62   * Search the mount table looking for
63   * the correct (ie last) matching entry
64   */
65  while (mp) {
66    if (STREQ(mp->mnt->mnt_dir, mntdir))
67      mp_save = mp;
68    mp = mp->mnext;
69  }
70
71  if (mp_save) {
72    dlog("Trying unmount(%s)", mp_save->mnt->mnt_dir);
73
74#ifdef MOUNT_TABLE_ON_FILE
75    /*
76     * This unmount may hang leaving this process with an exclusive lock on
77     * /etc/mtab. Therefore it is necessary to unlock mtab, do the unmount,
78     * then lock mtab (again) and reread it and finally update it.
79     */
80    unlock_mntlist();
81#endif /* MOUNT_TABLE_ON_FILE */
82
83#ifdef NEED_AUTOFS_SPACE_HACK
84    if (unmount_flags & AMU_UMOUNT_AUTOFS) {
85      char *mnt_dir_save = mp_save->mnt->mnt_dir;
86      mp_save->mnt->mnt_dir = autofs_strdup_space_hack(mnt_dir_save);
87      error = UNMOUNT_TRAP(mp_save->mnt);
88      XFREE(mp_save->mnt->mnt_dir);
89      mp_save->mnt->mnt_dir = mnt_dir_save;
90    } else
91#endif /* NEED_AUTOFS_SPACE_HACK */
92      error = UNMOUNT_TRAP(mp_save->mnt);
93    if (error < 0) {
94      switch ((error = errno)) {
95      case EINVAL:
96      case ENOTBLK:
97	plog(XLOG_WARNING, "unmount: %s is not mounted", mp_save->mnt->mnt_dir);
98	error = 0;		/* Not really an error */
99	break;
100
101      case ENOENT:
102	/*
103	 * This could happen if the kernel insists on following symlinks
104	 * when we try to unmount a direct mountpoint. We need to propagate
105	 * the error up so that the top layers know it failed and don't
106	 * try to rmdir() the mountpoint or other silly things.
107	 */
108	plog(XLOG_ERROR, "mount point %s: %m", mp_save->mnt->mnt_dir);
109	break;
110
111#if defined(MNT2_GEN_OPT_FORCE) && defined(HAVE_UMOUNT2)
112      case EBUSY:
113      case EIO:
114      case ESTALE:
115	/* caller determines if forced unmounts should be used */
116	if (unmount_flags & AMU_UMOUNT_FORCE) {
117	  error = umount2_fs(mntdir, unmount_flags);
118	  if (error < 0)
119	    error = errno;
120	  else
121	    break;		/* all is OK */
122	}
123	/* fallthrough */
124#endif /* MNT2_GEN_OPT_FORCE && HAVE_UMOUNT2 */
125      default:
126	dlog("%s: unmount: %m", mp_save->mnt->mnt_dir);
127	break;
128      }
129    }
130    dlog("Finished unmount(%s)", mp_save->mnt->mnt_dir);
131
132    if (!error) {
133#ifdef MOUNT_TABLE_ON_FILE
134      free_mntlist(mlist);
135      mp = mlist = read_mtab(mntdir, mnttabname);
136
137      /*
138       * Search the mount table looking for
139       * the correct (ie last) matching entry
140       */
141      mp_save = NULL;
142      while (mp) {
143	if (STREQ(mp->mnt->mnt_dir, mntdir))
144	  mp_save = mp;
145	mp = mp->mnext;
146      }
147
148      if (mp_save) {
149	mnt_free(mp_save->mnt);
150	mp_save->mnt = NULL;
151	rewrite_mtab(mlist, mnttabname);
152      }
153#endif /* MOUNT_TABLE_ON_FILE */
154    }
155
156  } else {
157
158    plog(XLOG_ERROR, "Couldn't find how to unmount %s", mntdir);
159    /*
160     * Assume it is already unmounted
161     */
162    error = 0;
163  } /* end of "if (mp_save)" statement */
164
165  free_mntlist(mlist);
166
167  return error;
168}
169
170
171#if defined(MNT2_GEN_OPT_FORCE) && defined(HAVE_UMOUNT2)
172/* force unmount, no questions asked, without touching mnttab file */
173int
174umount2_fs(const char *mntdir, u_int unmount_flags)
175{
176  int error = 0;
177
178  if (unmount_flags & AMU_UMOUNT_FORCE) {
179    plog(XLOG_INFO, "umount2_fs: trying unmount/forced on %s", mntdir);
180    error = umount2(mntdir, MNT2_GEN_OPT_FORCE); /* Solaris */
181    if (error < 0 && (errno == EINVAL || errno == ENOENT))
182      error = 0;		/* ignore EINVAL/ENOENT */
183    if (error < 0)
184      plog(XLOG_WARNING, "%s: unmount/force: %m", mntdir);
185    else
186      dlog("%s: unmount/force: OK", mntdir);
187  }
188  return error;
189}
190#endif /* MNT2_GEN_OPT_FORCE && HAVE_UMOUNT2 */
191