GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/umount/umount.c Lines: 53 164 32.3 %
Date: 2017-11-13 Branches: 37 132 28.0 %

Line Branch Exec Source
1
/*	$OpenBSD: umount.c,v 1.27 2016/12/16 17:44:59 krw Exp $	*/
2
/*	$NetBSD: umount.c,v 1.16 1996/05/11 14:13:55 mycroft Exp $	*/
3
4
/*-
5
 * Copyright (c) 1980, 1989, 1993
6
 *	The Regents of the University of California.  All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 * 3. Neither the name of the University nor the names of its contributors
17
 *    may be used to endorse or promote products derived from this software
18
 *    without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 * SUCH DAMAGE.
31
 */
32
33
#include <sys/stat.h>
34
#include <sys/mount.h>
35
#include <sys/time.h>
36
#include <sys/socket.h>
37
#include <sys/socketvar.h>
38
39
#include <netdb.h>
40
#include <rpc/rpc.h>
41
#include <rpc/pmap_clnt.h>
42
#include <rpc/pmap_prot.h>
43
#include <nfs/rpcv2.h>
44
45
#include <err.h>
46
#include <stdio.h>
47
#include <stdlib.h>
48
#include <string.h>
49
#include <unistd.h>
50
#include <limits.h>
51
#include <util.h>
52
53
typedef enum { MNTON, MNTFROM } mntwhat;
54
55
int	fflag, verbose;
56
char	**typelist = NULL;
57
char	*nfshost;
58
59
char	*getmntname(char *, mntwhat, char *);
60
void	 maketypelist(char *);
61
int	 selected(const char *);
62
int	 namematch(struct hostent *);
63
int	 umountall(void);
64
int	 umountfs(char *);
65
void	 usage(void);
66
int	 xdr_dir(XDR *, char *);
67
68
int
69
main(int argc, char *argv[])
70
{
71
	int all, ch, errs;
72
73
	/* Start disks transferring immediately. */
74
24
	sync();
75
76
	all = 0;
77
40
	while ((ch = getopt(argc, argv, "afh:t:v")) != -1)
78

8
		switch (ch) {
79
		case 'a':
80
			all = 1;
81
			break;
82
		case 'f':
83
8
			fflag = MNT_FORCE;
84
8
			break;
85
		case 'h':	/* -h implies -a. */
86
			all = 1;
87
			nfshost = optarg;
88
			break;
89
		case 't':
90
			if (typelist != NULL)
91
				errx(1, "only one -t option may be specified.");
92
			maketypelist(optarg);
93
			break;
94
		case 'v':
95
			verbose = 1;
96
			break;
97
		default:
98
			usage();
99
			/* NOTREACHED */
100
		}
101
12
	argc -= optind;
102
12
	argv += optind;
103
104

24
	if ((argc == 0 && !all) || (argc != 0 && all))
105
		usage();
106
107
	/* -h implies "-t nfs" if no -t flag. */
108
12
	if ((nfshost != NULL) && (typelist == NULL))
109
		maketypelist(MOUNT_NFS);
110
111
12
	if (all)
112
		errs = umountall();
113
	else
114
48
		for (errs = 0; *argv != NULL; ++argv)
115
12
			if (umountfs(*argv) != 0)
116
8
				errs = 1;
117
12
	return (errs);
118
}
119
120
int
121
umountall(void)
122
{
123
	struct statfs *fs;
124
	int n;
125
	int rval;
126
127
	n = getmntinfo(&fs, MNT_NOWAIT);
128
	if (n == 0)
129
		err(1, NULL);
130
131
	rval = 0;
132
	while (--n >= 0) {
133
		/* Ignore the root. */
134
		if (strncmp(fs[n].f_mntonname, "/", MNAMELEN) == 0)
135
			continue;
136
		if (!selected(fs[n].f_fstypename))
137
			continue;
138
		if (umountfs(fs[n].f_mntonname))
139
			rval = 1;
140
	}
141
	return (rval);
142
}
143
144
int
145
umountfs(char *oname)
146
{
147
	struct hostent *hp;
148
#ifndef NO_NFS
149
24
	struct sockaddr_in saddr;
150
12
	struct timeval pertry, try;
151
	CLIENT *clp;
152
12
	int so;
153
#endif
154
12
	struct stat sb;
155
	char *delimp, *hostp, *mntpt;
156
12
	char *name, *newname, rname[PATH_MAX], type[MFSNAMELEN];
157
158

24
	if (isduid(oname, 0) || realpath(oname, rname) == NULL)
159
		mntpt = name = oname;
160
	else
161
		mntpt = name = rname;
162
	newname = NULL;
163
164
	/* If we can stat the file, check to see if it is a device or non-dir */
165
12
	if (stat(name, &sb) == 0) {
166
12
	    if (S_ISBLK(sb.st_mode)) {
167
8
		if ((mntpt = getmntname(name, MNTON, type)) == NULL) {
168
8
			warnx("%s: not currently mounted", name);
169
8
			return (1);
170
		}
171
4
	    } else if (!S_ISDIR(sb.st_mode)) {
172
		warnx("%s: not a directory or special device", name);
173
		return (1);
174
	    }
175
	}
176
177
	/*
178
	 * Look up the name in the mount table.
179
	 * 99.9% of the time the path in the kernel is the one
180
	 * realpath() returns but check the original just in case...
181
	 */
182

4
	if (!(newname = getmntname(name, MNTFROM, type)) &&
183
	    !(mntpt = getmntname(name, MNTON, type)) ) {
184
		mntpt = oname;
185
		if (!(newname = getmntname(oname, MNTFROM, type)) &&
186
		    !(mntpt = getmntname(oname, MNTON, type))) {
187
			warnx("%s: not currently mounted", oname);
188
			return (1);
189
		}
190
	}
191
4
	if (newname)
192
4
		name = newname;
193
194
4
	if (!selected(type))
195
		return (1);
196
197
4
	if (!strncmp(type, MOUNT_NFS, MFSNAMELEN)) {
198
		if ((delimp = strchr(name, '@')) != NULL) {
199
			hostp = delimp + 1;
200
			*delimp = '\0';
201
			hp = gethostbyname(hostp);
202
			*delimp = '@';
203
		} else if ((delimp = strchr(name, ':')) != NULL) {
204
			*delimp = '\0';
205
			hostp = name;
206
			hp = gethostbyname(hostp);
207
			name = delimp + 1;
208
			*delimp = ':';
209
		} else
210
			hp = NULL;
211
		if (!namematch(hp))
212
			return (1);
213
	}
214
215
4
	if (verbose)
216
		printf("%s: unmount from %s\n", name, mntpt);
217
218
4
	if (unmount(mntpt, fflag) < 0) {
219
		warn("%s", mntpt);
220
		return (1);
221
	}
222
223
#ifndef NO_NFS
224

8
	if (!strncmp(type, MOUNT_NFS, MFSNAMELEN) &&
225
4
	    (hp != NULL) && !(fflag & MNT_FORCE)) {
226
		enum clnt_stat clnt_stat;
227
228
		*delimp = '\0';
229
		memset(&saddr, 0, sizeof(saddr));
230
		saddr.sin_family = AF_INET;
231
		saddr.sin_port = 0;
232
		memmove(&saddr.sin_addr, hp->h_addr, hp->h_length);
233
		pertry.tv_sec = 3;
234
		pertry.tv_usec = 0;
235
		so = RPC_ANYSOCK;
236
		if ((clp = clntudp_create(&saddr,
237
		    RPCPROG_MNT, RPCMNT_VER1, pertry, &so)) == NULL) {
238
			clnt_pcreateerror("Cannot MNT RPC");
239
			return (1);
240
		}
241
		clp->cl_auth = authunix_create_default();
242
		try.tv_sec = 20;
243
		try.tv_usec = 0;
244
		clnt_stat = clnt_call(clp,
245
		    RPCMNT_UMOUNT, xdr_dir, name, xdr_void, (caddr_t)0, try);
246
		if (clnt_stat != RPC_SUCCESS) {
247
			clnt_perror(clp, "Bad MNT RPC");
248
			return (1);
249
		}
250
		auth_destroy(clp->cl_auth);
251
		clnt_destroy(clp);
252
	}
253
#endif
254
4
	return (0);
255
12
}
256
257
char *
258
getmntname(char *name, mntwhat what, char *type)
259
{
260
24
	struct statfs *mntbuf;
261
	int n;
262
263
12
	if ((n = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) {
264
		warn("getmntinfo");
265
		return (NULL);
266
	}
267
168
	while (--n >= 0) {
268

148
		if ((what == MNTON) &&
269
72
		    (strncmp(mntbuf[n].f_mntfromname, name, MNAMELEN) == 0 ||
270
72
		     strncmp(mntbuf[n].f_mntfromspec, name, MNAMELEN) == 0)) {
271
			if (type)
272
				memcpy(type, mntbuf[n].f_fstypename,
273
				    sizeof(mntbuf[n].f_fstypename));
274
			return (mntbuf[n].f_mntonname);
275
		}
276

80
		if ((what == MNTFROM) &&
277
4
		    (strncmp(mntbuf[n].f_mntonname, name, MNAMELEN) == 0)) {
278
4
			if (type)
279
4
				memcpy(type, mntbuf[n].f_fstypename,
280
				    sizeof(mntbuf[n].f_fstypename));
281
4
			return (mntbuf[n].f_mntfromname);
282
		}
283
	}
284
8
	return (NULL);
285
12
}
286
287
static enum { IN_LIST, NOT_IN_LIST } which;
288
289
int
290
selected(const char *type)
291
{
292
	char **av;
293
294
	/* If no type specified, it's always selected. */
295
8
	if (typelist == NULL)
296
4
		return (1);
297
	for (av = typelist; *av != NULL; ++av)
298
		if (!strncmp(type, *av, MFSNAMELEN))
299
			return (which == IN_LIST ? 1 : 0);
300
	return (which == IN_LIST ? 0 : 1);
301
4
}
302
303
void
304
maketypelist(char *fslist)
305
{
306
	int i;
307
	char *nextcp, **av;
308
309
	if ((fslist == NULL) || (fslist[0] == '\0'))
310
		errx(1, "empty type list");
311
312
	/*
313
	 * XXX
314
	 * Note: the syntax is "noxxx,yyy" for no xxx's and
315
	 * no yyy's, not the more intuitive "noxxx,noyyy".
316
	 */
317
	if (fslist[0] == 'n' && fslist[1] == 'o') {
318
		fslist += 2;
319
		which = NOT_IN_LIST;
320
	} else
321
		which = IN_LIST;
322
323
	/* Count the number of types. */
324
	for (i = 1, nextcp = fslist; (nextcp = strchr(nextcp, ',')); i++)
325
		++nextcp;
326
327
	/* Build an array of that many types. */
328
	if ((av = typelist = calloc(i + 1, sizeof(char *))) == NULL)
329
		err(1, NULL);
330
	av[0] = fslist;
331
	for (i = 1, nextcp = fslist; (nextcp = strchr(nextcp, ',')); i++) {
332
		*nextcp = '\0';
333
		av[i] = ++nextcp;
334
	}
335
	/* Terminate the array. */
336
	av[i] = NULL;
337
}
338
339
int
340
namematch(struct hostent *hp)
341
{
342
	char *cp, **np;
343
344
	if ((hp == NULL) || (nfshost == NULL))
345
		return (1);
346
347
	if (strcasecmp(nfshost, hp->h_name) == 0)
348
		return (1);
349
350
	if ((cp = strchr(hp->h_name, '.')) != NULL) {
351
		*cp = '\0';
352
		if (strcasecmp(nfshost, hp->h_name) == 0)
353
			return (1);
354
	}
355
	for (np = hp->h_aliases; *np; np++) {
356
		if (strcasecmp(nfshost, *np) == 0)
357
			return (1);
358
		if ((cp = strchr(*np, '.')) != NULL) {
359
			*cp = '\0';
360
			if (strcasecmp(nfshost, *np) == 0)
361
				return (1);
362
		}
363
	}
364
	return (0);
365
}
366
367
#ifndef NO_NFS
368
/*
369
 * xdr routines for mount rpc's
370
 */
371
int
372
xdr_dir(XDR *xdrsp, char *dirp)
373
{
374
	return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
375
}
376
#endif
377
378
void
379
usage(void)
380
{
381
	fprintf(stderr,
382
	    "usage: %s\n       %s\n",
383
	    "umount [-fv] special | node",
384
	    "umount -a [-fv] [-h host] [-t type]");
385
	exit(1);
386
}