GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/umount/umount.c Lines: 0 158 0.0 %
Date: 2016-12-06 Branches: 0 134 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: umount.c,v 1.26 2015/01/16 06:40:01 deraadt 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
	sync();
75
76
	all = 0;
77
	while ((ch = getopt(argc, argv, "afh:t:v")) != -1)
78
		switch (ch) {
79
		case 'a':
80
			all = 1;
81
			break;
82
		case 'f':
83
			fflag = MNT_FORCE;
84
			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
	argc -= optind;
102
	argv += optind;
103
104
	if ((argc == 0 && !all) || (argc != 0 && all))
105
		usage();
106
107
	/* -h implies "-t nfs" if no -t flag. */
108
	if ((nfshost != NULL) && (typelist == NULL))
109
		maketypelist(MOUNT_NFS);
110
111
	if (all)
112
		errs = umountall();
113
	else
114
		for (errs = 0; *argv != NULL; ++argv)
115
			if (umountfs(*argv) != 0)
116
				errs = 1;
117
	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
	struct sockaddr_in saddr;
149
	struct stat sb;
150
	struct timeval pertry, try;
151
	CLIENT *clp;
152
	int so;
153
	char *delimp, *hostp, *mntpt;
154
	char *name, *newname, rname[PATH_MAX], type[MFSNAMELEN];
155
156
	if (isduid(oname, 0) || realpath(oname, rname) == NULL)
157
		mntpt = name = oname;
158
	else
159
		mntpt = name = rname;
160
	newname = NULL;
161
162
	/* If we can stat the file, check to see if it is a device or non-dir */
163
	if (stat(name, &sb) == 0) {
164
	    if (S_ISBLK(sb.st_mode)) {
165
		if ((mntpt = getmntname(name, MNTON, type)) == NULL) {
166
			warnx("%s: not currently mounted", name);
167
			return (1);
168
		}
169
	    } else if (!S_ISDIR(sb.st_mode)) {
170
		warnx("%s: not a directory or special device", name);
171
		return (1);
172
	    }
173
	}
174
175
	/*
176
	 * Look up the name in the mount table.
177
	 * 99.9% of the time the path in the kernel is the one
178
	 * realpath() returns but check the original just in case...
179
	 */
180
	if (!(newname = getmntname(name, MNTFROM, type)) &&
181
	    !(mntpt = getmntname(name, MNTON, type)) ) {
182
		mntpt = oname;
183
		if (!(newname = getmntname(oname, MNTFROM, type)) &&
184
		    !(mntpt = getmntname(oname, MNTON, type))) {
185
			warnx("%s: not currently mounted", oname);
186
			return (1);
187
		}
188
	}
189
	if (newname)
190
		name = newname;
191
192
	if (!selected(type))
193
		return (1);
194
195
	if (!strncmp(type, MOUNT_NFS, MFSNAMELEN)) {
196
		if ((delimp = strchr(name, '@')) != NULL) {
197
			hostp = delimp + 1;
198
			*delimp = '\0';
199
			hp = gethostbyname(hostp);
200
			*delimp = '@';
201
		} else if ((delimp = strchr(name, ':')) != NULL) {
202
			*delimp = '\0';
203
			hostp = name;
204
			hp = gethostbyname(hostp);
205
			name = delimp + 1;
206
			*delimp = ':';
207
		} else
208
			hp = NULL;
209
		if (!namematch(hp))
210
			return (1);
211
	}
212
213
	if (verbose)
214
		printf("%s: unmount from %s\n", name, mntpt);
215
216
	if (unmount(mntpt, fflag) < 0) {
217
		warn("%s", mntpt);
218
		return (1);
219
	}
220
221
#ifndef NO_NFS
222
	if (!strncmp(type, MOUNT_NFS, MFSNAMELEN) &&
223
	    (hp != NULL) && !(fflag & MNT_FORCE)) {
224
		enum clnt_stat clnt_stat;
225
226
		*delimp = '\0';
227
		memset(&saddr, 0, sizeof(saddr));
228
		saddr.sin_family = AF_INET;
229
		saddr.sin_port = 0;
230
		memmove(&saddr.sin_addr, hp->h_addr, hp->h_length);
231
		pertry.tv_sec = 3;
232
		pertry.tv_usec = 0;
233
		so = RPC_ANYSOCK;
234
		if ((clp = clntudp_create(&saddr,
235
		    RPCPROG_MNT, RPCMNT_VER1, pertry, &so)) == NULL) {
236
			clnt_pcreateerror("Cannot MNT RPC");
237
			return (1);
238
		}
239
		clp->cl_auth = authunix_create_default();
240
		try.tv_sec = 20;
241
		try.tv_usec = 0;
242
		clnt_stat = clnt_call(clp,
243
		    RPCMNT_UMOUNT, xdr_dir, name, xdr_void, (caddr_t)0, try);
244
		if (clnt_stat != RPC_SUCCESS) {
245
			clnt_perror(clp, "Bad MNT RPC");
246
			return (1);
247
		}
248
		auth_destroy(clp->cl_auth);
249
		clnt_destroy(clp);
250
	}
251
#endif
252
	return (0);
253
}
254
255
char *
256
getmntname(char *name, mntwhat what, char *type)
257
{
258
	struct statfs *mntbuf;
259
	int n;
260
261
	if ((n = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) {
262
		warn("getmntinfo");
263
		return (NULL);
264
	}
265
	while (--n >= 0) {
266
		if ((what == MNTON) &&
267
		    (strncmp(mntbuf[n].f_mntfromname, name, MNAMELEN) == 0 ||
268
		     strncmp(mntbuf[n].f_mntfromspec, name, MNAMELEN) == 0)) {
269
			if (type)
270
				memcpy(type, mntbuf[n].f_fstypename,
271
				    sizeof(mntbuf[n].f_fstypename));
272
			return (mntbuf[n].f_mntonname);
273
		}
274
		if ((what == MNTFROM) &&
275
		    (strncmp(mntbuf[n].f_mntonname, name, MNAMELEN) == 0)) {
276
			if (type)
277
				memcpy(type, mntbuf[n].f_fstypename,
278
				    sizeof(mntbuf[n].f_fstypename));
279
			return (mntbuf[n].f_mntfromname);
280
		}
281
	}
282
	return (NULL);
283
}
284
285
static enum { IN_LIST, NOT_IN_LIST } which;
286
287
int
288
selected(const char *type)
289
{
290
	char **av;
291
292
	/* If no type specified, it's always selected. */
293
	if (typelist == NULL)
294
		return (1);
295
	for (av = typelist; *av != NULL; ++av)
296
		if (!strncmp(type, *av, MFSNAMELEN))
297
			return (which == IN_LIST ? 1 : 0);
298
	return (which == IN_LIST ? 0 : 1);
299
}
300
301
void
302
maketypelist(char *fslist)
303
{
304
	int i;
305
	char *nextcp, **av;
306
307
	if ((fslist == NULL) || (fslist[0] == '\0'))
308
		errx(1, "empty type list");
309
310
	/*
311
	 * XXX
312
	 * Note: the syntax is "noxxx,yyy" for no xxx's and
313
	 * no yyy's, not the more intuitive "noxxx,noyyy".
314
	 */
315
	if (fslist[0] == 'n' && fslist[1] == 'o') {
316
		fslist += 2;
317
		which = NOT_IN_LIST;
318
	} else
319
		which = IN_LIST;
320
321
	/* Count the number of types. */
322
	for (i = 1, nextcp = fslist; (nextcp = strchr(nextcp, ',')); i++)
323
		++nextcp;
324
325
	/* Build an array of that many types. */
326
	if ((av = typelist = calloc(i + 1, sizeof(char *))) == NULL)
327
		err(1, NULL);
328
	av[0] = fslist;
329
	for (i = 1, nextcp = fslist; (nextcp = strchr(nextcp, ',')); i++) {
330
		*nextcp = '\0';
331
		av[i] = ++nextcp;
332
	}
333
	/* Terminate the array. */
334
	av[i] = NULL;
335
}
336
337
int
338
namematch(struct hostent *hp)
339
{
340
	char *cp, **np;
341
342
	if ((hp == NULL) || (nfshost == NULL))
343
		return (1);
344
345
	if (strcasecmp(nfshost, hp->h_name) == 0)
346
		return (1);
347
348
	if ((cp = strchr(hp->h_name, '.')) != NULL) {
349
		*cp = '\0';
350
		if (strcasecmp(nfshost, hp->h_name) == 0)
351
			return (1);
352
	}
353
	for (np = hp->h_aliases; *np; np++) {
354
		if (strcasecmp(nfshost, *np) == 0)
355
			return (1);
356
		if ((cp = strchr(*np, '.')) != NULL) {
357
			*cp = '\0';
358
			if (strcasecmp(nfshost, *np) == 0)
359
				return (1);
360
		}
361
	}
362
	return (0);
363
}
364
365
#ifndef NO_NFS
366
/*
367
 * xdr routines for mount rpc's
368
 */
369
int
370
xdr_dir(XDR *xdrsp, char *dirp)
371
{
372
	return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
373
}
374
#endif
375
376
void
377
usage(void)
378
{
379
	fprintf(stderr,
380
	    "usage: %s\n       %s\n",
381
	    "umount [-fv] special | node",
382
	    "umount -a [-fv] [-h host] [-t type]");
383
	exit(1);
384
}