GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/mount/mount.c Lines: 42 385 10.9 %
Date: 2017-11-07 Branches: 27 353 7.6 %

Line Branch Exec Source
1
/*	$OpenBSD: mount.c,v 1.71 2017/02/06 17:15:56 tb Exp $	*/
2
/*	$NetBSD: mount.c,v 1.24 1995/11/18 03:34:29 cgd Exp $	*/
3
4
/*
5
 * Copyright (c) 1980, 1989, 1993, 1994
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/types.h>
34
#include <sys/mount.h>
35
#include <sys/socket.h>
36
#include <sys/wait.h>
37
38
#include <nfs/rpcv2.h>
39
#include <nfs/nfsproto.h>
40
#include <nfs/nfs.h>
41
42
#include <err.h>
43
#include <errno.h>
44
#include <fstab.h>
45
#include <netdb.h>
46
#include <signal.h>
47
#include <stdio.h>
48
#include <stdlib.h>
49
#include <string.h>
50
#include <unistd.h>
51
#include <limits.h>
52
#include <util.h>
53
54
#include "pathnames.h"
55
56
int	debug, verbose, skip;
57
char	**typelist = NULL;
58
enum { NONET_FILTER, NET_FILTER } filter = NONET_FILTER;
59
60
int	selected(const char *);
61
char   *catopt(char *, const char *);
62
char   *flags2opts(u_int32_t);
63
struct statfs
64
       *getmntpt(const char *);
65
int	hasopt(const char *, const char *);
66
void	maketypelist(char *);
67
void	mangle(char *, int *, const char **, int);
68
int	mountfs(const char *, const char *, const char *, const char *,
69
	    const char *, int);
70
void	prmount(struct statfs *);
71
int	disklabelcheck(struct fstab *);
72
__dead void	usage(void);
73
74
/* Map from mount options to printable formats. */
75
static struct opt {
76
	int o_opt;
77
	int o_silent;
78
	const char *o_name;
79
	const char *o_optname;
80
} optnames[] = {
81
	{ MNT_ASYNC,		0,	"asynchronous",		"async" },
82
	{ MNT_DEFEXPORTED,	1,	"exported to the world", "" },
83
	{ MNT_EXPORTED,		0,	"NFS exported",		"" },
84
	{ MNT_EXPORTANON,	1,	"anon uid mapping",	"" },
85
	{ MNT_EXRDONLY,		1,	"exported read-only",	"" },
86
	{ MNT_LOCAL,		0,	"local",		"" },
87
	{ MNT_NOATIME,		0,	"noatime",		"noatime" },
88
	{ MNT_NODEV,		0,	"nodev",		"nodev" },
89
	{ MNT_NOEXEC,		0,	"noexec",		"noexec" },
90
	{ MNT_NOSUID,		0,	"nosuid",		"nosuid" },
91
	{ MNT_NOPERM,		0,	"noperm",		"noperm" },
92
	{ MNT_WXALLOWED,	0,	"wxallowed",		"wxallowed" },
93
	{ MNT_QUOTA,		0,	"with quotas",		"" },
94
	{ MNT_RDONLY,		0,	"read-only",		"ro" },
95
	{ MNT_ROOTFS,		1,	"root file system",	"" },
96
	{ MNT_SYNCHRONOUS,	0,	"synchronous",		"sync" },
97
	{ MNT_SOFTDEP,		0,	"softdep",		"softdep" },
98
	{ 0,			0,	"",			"" }
99
};
100
101
int
102
main(int argc, char * const argv[])
103
{
104
	const char *mntonname, *vfstype;
105
	struct fstab *fs;
106
218
	struct statfs *mntbuf;
107
	FILE *mountdfp;
108
109
	pid_t pid;
109
	int all, ch, forceall, i, mntsize, rval, new;
110
109
	char *options, mntpath[PATH_MAX];
111
112
	all = forceall = 0;
113
	options = NULL;
114
	vfstype = "ffs";
115
218
	while ((ch = getopt(argc, argv, "AadfNo:rswt:uv")) != -1)
116
		switch (ch) {
117
		case 'A':
118
			all = forceall = 1;
119
			break;
120
		case 'a':
121
			all = 1;
122
			break;
123
		case 'd':
124
			debug = 1;
125
			break;
126
		case 'f':
127
			if (!hasopt(options, "force"))
128
				options = catopt(options, "force");
129
			break;
130
		case 'N':
131
			filter = NET_FILTER;
132
			break;
133
		case 'o':
134
			if (*optarg)
135
				options = catopt(options, optarg);
136
			break;
137
		case 'r':
138
			if (!hasopt(options, "ro"))
139
				options = catopt(options, "ro");
140
			break;
141
		case 's':
142
			skip = 1;
143
			break;
144
		case 't':
145
			if (typelist != NULL)
146
				errx(1, "only one -t option may be specified.");
147
			maketypelist(optarg);
148
			vfstype = optarg;
149
			break;
150
		case 'u':
151
			if (!hasopt(options, "update"))
152
				options = catopt(options, "update");
153
			break;
154
		case 'v':
155
			verbose = 1;
156
			break;
157
		case 'w':
158
			if (!hasopt(options, "rw"))
159
				options = catopt(options, "rw");
160
			break;
161
		case '?':
162
		default:
163
			usage();
164
		}
165
109
	argc -= optind;
166
109
	argv += optind;
167
168
109
	if (typelist == NULL && argc == 2) {
169
		/*
170
		 * If -t flag has not been specified, and spec contains either
171
		 * a ':' or a '@' then assume that an NFS filesystem is being
172
		 * specified ala Sun.  If not, check the disklabel for a
173
		 * known filesystem type.
174
		 */
175
		if (strpbrk(argv[0], ":@") != NULL)
176
			vfstype = "nfs";
177
		else {
178
			char *labelfs = readlabelfs(argv[0], 0);
179
			if (labelfs != NULL)
180
				vfstype = labelfs;
181
		}
182
	}
183
184
109
	if (pledge("stdio rpath disklabel proc exec flock cpath wpath", NULL) == -1)
185
		err(1, "pledge");
186
187
#define	BADTYPE(type)							\
188
	(strcmp(type, FSTAB_RO) &&					\
189
	    strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ))
190
191
	rval = 0;
192
	new = 0;
193

109
	switch (argc) {
194
	case 0:
195
109
		if (all)
196
			while ((fs = getfsent()) != NULL) {
197
				if (BADTYPE(fs->fs_type))
198
					continue;
199
				switch (filter) {
200
				case NET_FILTER:
201
					if (!hasopt(fs->fs_mntops, "net"))
202
						continue;
203
					break;
204
				case NONET_FILTER:
205
					if (hasopt(fs->fs_mntops, "net"))
206
						continue;
207
					break;
208
				}
209
				if (!selected(fs->fs_vfstype))
210
					continue;
211
				if (hasopt(fs->fs_mntops, "noauto"))
212
					continue;
213
				if (disklabelcheck(fs))
214
					continue;
215
				if (mountfs(fs->fs_vfstype, fs->fs_spec,
216
				    fs->fs_file, options,
217
				    fs->fs_mntops, !forceall))
218
					rval = 1;
219
				else
220
					++new;
221
			}
222
		else {
223
109
			if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0)
224
				err(1, "getmntinfo");
225
2180
			for (i = 0; i < mntsize; i++) {
226
981
				if (!selected(mntbuf[i].f_fstypename))
227
					continue;
228
981
				prmount(&mntbuf[i]);
229
981
			}
230
109
			return (rval);
231
		}
232
		break;
233
	case 1:
234
		if (typelist != NULL)
235
			usage();
236
237
		if (realpath(*argv, mntpath) == NULL && strpbrk(argv[0], ":@") == NULL)
238
			err(1, "realpath %s", *argv);
239
		if (hasopt(options, "update")) {
240
			if ((mntbuf = getmntpt(mntpath)) == NULL)
241
				errx(1,
242
				    "unknown special file or file system %s.",
243
				    *argv);
244
			if ((mntbuf->f_flags & MNT_ROOTFS) &&
245
			    !strcmp(mntbuf->f_mntfromname, "root_device")) {
246
				/* Lookup fstab for name of root device. */
247
				fs = getfsfile(mntbuf->f_mntonname);
248
				if (fs == NULL)
249
					errx(1,
250
					    "can't find fstab entry for %s.",
251
					    *argv);
252
			} else {
253
				if ((fs = malloc(sizeof(*fs))) == NULL)
254
					err(1, NULL);
255
				fs->fs_vfstype = mntbuf->f_fstypename;
256
				fs->fs_spec = mntbuf->f_mntfromname;
257
			}
258
			/*
259
			 * It's an update, ignore the fstab file options.
260
			 * Get the current options, so we can change only
261
			 * the options which given via a command line.
262
			 */
263
			fs->fs_mntops = flags2opts(mntbuf->f_flags);
264
			mntonname = mntbuf->f_mntonname;
265
		} else {
266
			if ((fs = getfsfile(mntpath)) == NULL &&
267
			    (fs = getfsspec(mntpath)) == NULL &&
268
			    (fs = getfsspec(*argv)) == NULL)
269
				errx(1, "can't find fstab entry for %s.",
270
				    *argv);
271
			if (BADTYPE(fs->fs_type))
272
				errx(1, "%s has unknown file system type.",
273
				    *argv);
274
			mntonname = fs->fs_file;
275
		}
276
		rval = mountfs(fs->fs_vfstype, fs->fs_spec,
277
		    mntonname, options, fs->fs_mntops, skip);
278
		break;
279
	case 2:
280
		rval = mountfs(vfstype, argv[0], argv[1], options, NULL, 0);
281
		break;
282
	default:
283
		usage();
284
	}
285
286
	/*
287
	 * If the mount was successfully, and done by root, tell mountd the
288
	 * good news.  Pid checks are probably unnecessary, but don't hurt.
289
	 * XXX This should be done from kernel.
290
	 */
291
	if ((rval == 0 || new) && getuid() == 0 &&
292
	    (mountdfp = fopen(_PATH_MOUNTDPID, "r")) != NULL) {
293
		if (fscanf(mountdfp, "%d", &pid) == 1 &&
294
		    pid > 0 && kill(pid, SIGHUP) == -1 && errno != ESRCH)
295
			err(1, "signal mountd");
296
		(void)fclose(mountdfp);
297
	}
298
299
	return (rval);
300
109
}
301
302
int
303
hasopt(const char *mntopts, const char *option)
304
{
305
	int found;
306
	char *opt, *optbuf;
307
308
	if (mntopts == NULL)
309
		return (0);
310
	if ((optbuf = strdup(mntopts)) == NULL)
311
		err(1, NULL);
312
	found = 0;
313
	for (opt = optbuf; !found && opt != NULL; strsep(&opt, ","))
314
		found = !strncmp(opt, option, strlen(option));
315
	free(optbuf);
316
	return (found);
317
}
318
319
/*
320
 * Convert mount(2) flags to list of mount(8) options.
321
 */
322
char*
323
flags2opts(u_int32_t flags)
324
{
325
	char	*optlist;
326
	struct opt *p;
327
328
	optlist = NULL;
329
	for (p = optnames; p->o_opt; p++) {
330
		if (flags & p->o_opt && *p->o_optname)
331
			optlist = catopt(optlist, p->o_optname);
332
	}
333
334
	return(optlist);
335
}
336
337
int
338
mountfs(const char *vfstype, const char *spec, const char *name,
339
    const char *options, const char *mntopts, int skipmounted)
340
{
341
	char *cp;
342
343
	/* List of directories containing mount_xxx subcommands. */
344
	static const char *edirs[] = {
345
		_PATH_SBIN,
346
		_PATH_USRSBIN,
347
		NULL
348
	};
349
	const char **argv, **edir;
350
	struct statfs sf;
351
	pid_t pid;
352
	int argc, i, status, argvsize;
353
	char *optbuf, execname[PATH_MAX], mntpath[PATH_MAX];
354
355
	if (realpath(name, mntpath) == NULL) {
356
		warn("realpath %s", name);
357
		return (1);
358
	}
359
360
	name = mntpath;
361
362
	if (mntopts == NULL)
363
		mntopts = "";
364
365
	if (options == NULL) {
366
		if (*mntopts == '\0')
367
			options = "rw";
368
		else {
369
			options = mntopts;
370
			mntopts = "";
371
		}
372
	}
373
374
	/* options follows after mntopts, so they get priority over mntopts */
375
	if ((cp = strdup(mntopts)) == NULL)
376
		err(1, NULL);
377
	optbuf = catopt(cp, options);
378
379
	if (strcmp(name, "/") == 0) {
380
		if (!hasopt(optbuf, "update"))
381
			optbuf = catopt(optbuf, "update");
382
	} else if (skipmounted) {
383
		if (statfs(name, &sf) < 0) {
384
			warn("statfs %s", name);
385
			return (1);
386
		}
387
		/* XXX can't check f_mntfromname, thanks to mfs, etc. */
388
		if (strncmp(name, sf.f_mntonname, MNAMELEN) == 0 &&
389
		    strncmp(vfstype, sf.f_fstypename, MFSNAMELEN) == 0) {
390
			if (verbose) {
391
				printf("%s", sf.f_mntfromname);
392
				if (strncmp(sf.f_mntfromname,
393
				    sf.f_mntfromspec, MNAMELEN) != 0)
394
					printf(" (%s)", sf.f_mntfromspec);
395
				printf(" on %s type %.*s: %s\n",
396
				    sf.f_mntonname,
397
				    MFSNAMELEN, sf.f_fstypename,
398
				    "already mounted");
399
			}
400
			return (0);
401
		}
402
	}
403
404
	argvsize = 64;
405
	if((argv = reallocarray(NULL, argvsize, sizeof(char *))) == NULL)
406
		err(1, NULL);
407
	argc = 0;
408
	argv[argc++] = NULL;	/* this should be a full path name */
409
	mangle(optbuf, &argc, argv, argvsize - 4);
410
	argv[argc++] = spec;
411
	argv[argc++] = name;
412
	argv[argc] = NULL;
413
414
	if (debug) {
415
		(void)printf("exec: mount_%s", vfstype);
416
		for (i = 1; i < argc; i++)
417
			(void)printf(" %s", argv[i]);
418
		(void)printf("\n");
419
		free(optbuf);
420
		free(argv);
421
		return (0);
422
	}
423
424
	switch ((pid = fork())) {
425
	case -1:				/* Error. */
426
		warn("fork");
427
		free(optbuf);
428
		free(argv);
429
		return (1);
430
	case 0:					/* Child. */
431
		/* Go find an executable. */
432
		edir = edirs;
433
		do {
434
			(void)snprintf(execname,
435
			    sizeof(execname), "%s/mount_%s", *edir, vfstype);
436
			argv[0] = execname;
437
			execv(execname, (char * const *)argv);
438
			if (errno != ENOENT)
439
				warn("exec %s for %s", execname, name);
440
		} while (*++edir != NULL);
441
442
		if (errno == ENOENT)
443
			warn("no mount helper program found for %s", vfstype);
444
		_exit(1);
445
	default:				/* Parent. */
446
		free(optbuf);
447
		free(argv);
448
449
		if (waitpid(pid, &status, 0) < 0) {
450
			warn("waitpid");
451
			return (1);
452
		}
453
454
		if (WIFEXITED(status)) {
455
			if (WEXITSTATUS(status) != 0)
456
				return (WEXITSTATUS(status));
457
		} else if (WIFSIGNALED(status)) {
458
			warnx("%s: %s", name, strsignal(WTERMSIG(status)));
459
			return (1);
460
		}
461
462
		if (verbose) {
463
			if (statfs(name, &sf) < 0) {
464
				warn("statfs %s", name);
465
				return (1);
466
			}
467
			prmount(&sf);
468
		}
469
		break;
470
	}
471
472
	return (0);
473
}
474
475
void
476
prmount(struct statfs *sf)
477
{
478
	int flags;
479
	struct opt *o;
480
	int f = 0;
481
482
1962
	printf("%s", sf->f_mntfromname);
483

981
	if (verbose &&
484
	    strncmp(sf->f_mntfromname, sf->f_mntfromspec, MNAMELEN) != 0)
485
		printf(" (%s)", sf->f_mntfromspec);
486
1962
	printf(" on %s type %.*s", sf->f_mntonname,
487
981
	    MFSNAMELEN, sf->f_fstypename);
488
489
981
	flags = sf->f_flags & MNT_VISFLAGMASK;
490

981
	if (verbose && !(flags & MNT_RDONLY))
491
		(void)printf("%s%s", !f++ ? " (" : ", ", "rw");
492

43491
	for (o = optnames; flags && o->o_opt; o++)
493
10137
		if (flags & o->o_opt) {
494
2616
			if (!o->o_silent)
495
5014
				(void)printf("%s%s", !f++ ? " (" : ", ",
496
2507
				    o->o_name);
497
2616
			flags &= ~o->o_opt;
498
2616
		}
499
981
	if (flags)
500
		(void)printf("%sunknown flag%s %#x", !f++ ? " (" : ", ",
501
		    flags & (flags - 1) ? "s" : "", flags);
502
503
504
981
	if (verbose) {
505
		char buf[26];
506
		time_t t = sf->f_ctime;
507
508
		ctime_r(&t, buf);
509
		buf[24] = '\0';
510
		printf(", ctime=%s", buf);
511
	}
512
513
	/*
514
	 * Filesystem-specific options
515
	 * We only print the "interesting" values unless in verbose
516
	 * mode in order to keep the signal/noise ratio high.
517
	 */
518
981
	if (strcmp(sf->f_fstypename, MOUNT_NFS) == 0) {
519
		struct protoent *pr;
520
		struct nfs_args *nfs_args = &sf->mount_info.nfs_args;
521
522
		(void)printf("%s%s", !f++ ? " (" : ", ",
523
		    (nfs_args->flags & NFSMNT_NFSV3) ? "v3" : "v2");
524
		if (nfs_args->proto && (pr = getprotobynumber(nfs_args->proto)))
525
			(void)printf("%s%s", !f++ ? " (" : ", ", pr->p_name);
526
		else
527
			(void)printf("%s%s", !f++ ? " (" : ", ",
528
			    (nfs_args->sotype == SOCK_DGRAM) ? "udp" : "tcp");
529
		if (nfs_args->flags & NFSMNT_SOFT)
530
			(void)printf("%s%s", !f++ ? " (" : ", ", "soft");
531
		else if (verbose)
532
			(void)printf("%s%s", !f++ ? " (" : ", ", "hard");
533
		if (nfs_args->flags & NFSMNT_INT)
534
			(void)printf("%s%s", !f++ ? " (" : ", ", "intr");
535
		if (nfs_args->flags & NFSMNT_NOCONN)
536
			(void)printf("%s%s", !f++ ? " (" : ", ", "noconn");
537
		if (nfs_args->flags & NFSMNT_RDIRPLUS)
538
			(void)printf("%s%s", !f++ ? " (" : ", ", "rdirplus");
539
		if (verbose || nfs_args->wsize != NFS_WSIZE)
540
			(void)printf("%s%s=%d", !f++ ? " (" : ", ",
541
			    "wsize", nfs_args->wsize);
542
		if (verbose || nfs_args->rsize != NFS_RSIZE)
543
			(void)printf("%s%s=%d", !f++ ? " (" : ", ",
544
			    "rsize", nfs_args->rsize);
545
		if (verbose || nfs_args->readdirsize != NFS_READDIRSIZE)
546
			(void)printf("%s%s=%d", !f++ ? " (" : ", ",
547
			    "rdirsize", nfs_args->readdirsize);
548
		if (verbose || nfs_args->timeo != 10) /* XXX */
549
			(void)printf("%s%s=%d", !f++ ? " (" : ", ",
550
			    "timeo", nfs_args->timeo);
551
		if (verbose || nfs_args->retrans != NFS_RETRANS)
552
			(void)printf("%s%s=%d", !f++ ? " (" : ", ",
553
			    "retrans", nfs_args->retrans);
554
		if (verbose || nfs_args->maxgrouplist != NFS_MAXGRPS)
555
			(void)printf("%s%s=%d", !f++ ? " (" : ", ",
556
			    "maxgrouplist", nfs_args->maxgrouplist);
557
		if (verbose || nfs_args->readahead != NFS_DEFRAHEAD)
558
			(void)printf("%s%s=%d", !f++ ? " (" : ", ",
559
			    "readahead", nfs_args->readahead);
560
		if (verbose) {
561
			(void)printf("%s%s=%d", !f++ ? " (" : ", ",
562
			    "acregmin", nfs_args->acregmin);
563
			(void)printf(", %s=%d",
564
			    "acregmax", nfs_args->acregmax);
565
			(void)printf(", %s=%d",
566
			    "acdirmin", nfs_args->acdirmin);
567
			(void)printf(", %s=%d",
568
			    "acdirmax", nfs_args->acdirmax);
569
		}
570
981
	} else if (strcmp(sf->f_fstypename, MOUNT_MFS) == 0) {
571
		int headerlen;
572
		long blocksize;
573
		char *header;
574
575
		header = getbsize(&headerlen, &blocksize);
576
		(void)printf("%s%s=%lu %s", !f++ ? " (" : ", ",
577
		    "size", sf->mount_info.mfs_args.size / blocksize, header);
578
981
	} else if (strcmp(sf->f_fstypename, MOUNT_MSDOS) == 0) {
579
		struct msdosfs_args *msdosfs_args = &sf->mount_info.msdosfs_args;
580
581
		if (verbose || msdosfs_args->uid || msdosfs_args->gid)
582
			(void)printf("%s%s=%u, %s=%u", !f++ ? " (" : ", ",
583
			    "uid", msdosfs_args->uid, "gid", msdosfs_args->gid);
584
		if (verbose || msdosfs_args->mask != 0755)
585
			(void)printf("%s%s=0%o", !f++ ? " (" : ", ",
586
			    "mask", msdosfs_args->mask);
587
		if (msdosfs_args->flags & MSDOSFSMNT_SHORTNAME)
588
			(void)printf("%s%s", !f++ ? " (" : ", ", "short");
589
		if (msdosfs_args->flags & MSDOSFSMNT_LONGNAME)
590
			(void)printf("%s%s", !f++ ? " (" : ", ", "long");
591
		if (msdosfs_args->flags & MSDOSFSMNT_NOWIN95)
592
			(void)printf("%s%s", !f++ ? " (" : ", ", "nowin95");
593
981
	} else if (strcmp(sf->f_fstypename, MOUNT_CD9660) == 0) {
594
		struct iso_args *iso_args = &sf->mount_info.iso_args;
595
596
		if (iso_args->flags & ISOFSMNT_NORRIP)
597
			(void)printf("%s%s", !f++ ? " (" : ", ", "norrip");
598
		if (iso_args->flags & ISOFSMNT_GENS)
599
			(void)printf("%s%s", !f++ ? " (" : ", ", "gens");
600
		if (iso_args->flags & ISOFSMNT_EXTATT)
601
			(void)printf("%s%s", !f++ ? " (" : ", ", "extatt");
602
981
	} else if (strcmp(sf->f_fstypename, MOUNT_TMPFS) == 0) {
603
		struct tmpfs_args *tmpfs_args = &sf->mount_info.tmpfs_args;
604
605
		if (verbose || tmpfs_args->ta_root_uid || tmpfs_args->ta_root_gid)
606
			(void)printf("%s%s=%u, %s=%u", !f++ ? " (" : ", ",
607
			    "uid", tmpfs_args->ta_root_uid, "gid", tmpfs_args->ta_root_gid);
608
		if (verbose || tmpfs_args->ta_root_mode != 040755)
609
			(void)printf("%s%s=%04o", !f++ ? " (" : ", ",
610
			    "mode", tmpfs_args->ta_root_mode & 07777);
611
		if (verbose || tmpfs_args->ta_size_max)
612
			(void)printf("%s%s=%lu", !f++ ? " (" : ", ",
613
			    "size", (unsigned long)tmpfs_args->ta_size_max);
614
		if (verbose || tmpfs_args->ta_nodes_max)
615
			(void)printf("%s%s=%lu", !f++ ? " (" : ", ",
616
			    "inodes", (unsigned long)tmpfs_args->ta_nodes_max);
617
	}
618
981
	(void)printf(f ? ")\n" : "\n");
619
981
}
620
621
struct statfs *
622
getmntpt(const char *name)
623
{
624
	struct statfs *mntbuf;
625
	int i, mntsize;
626
627
	mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
628
	for (i = 0; i < mntsize; i++)
629
		if (strcmp(mntbuf[i].f_mntfromname, name) == 0 ||
630
		    strcmp(mntbuf[i].f_mntonname, name) == 0)
631
			return (&mntbuf[i]);
632
	return (NULL);
633
}
634
635
static enum { IN_LIST, NOT_IN_LIST } which;
636
637
int
638
selected(const char *type)
639
{
640
	char **av;
641
642
	/* If no type specified, it's always selected. */
643
1962
	if (typelist == NULL)
644
981
		return (1);
645
	for (av = typelist; *av != NULL; ++av)
646
		if (!strncmp(type, *av, MFSNAMELEN))
647
			return (which == IN_LIST ? 1 : 0);
648
	return (which == IN_LIST ? 0 : 1);
649
981
}
650
651
void
652
maketypelist(char *fslist)
653
{
654
	int i;
655
	char *nextcp, **av;
656
657
	if ((fslist == NULL) || (fslist[0] == '\0'))
658
		errx(1, "empty type list");
659
660
	/*
661
	 * XXX
662
	 * Note: the syntax is "noxxx,yyy" for no xxx's and
663
	 * no yyy's, not the more intuitive "noxxx,noyyy".
664
	 */
665
	if (fslist[0] == 'n' && fslist[1] == 'o') {
666
		fslist += 2;
667
		which = NOT_IN_LIST;
668
	} else
669
		which = IN_LIST;
670
671
	/* Count the number of types. */
672
	for (i = 1, nextcp = fslist; (nextcp = strchr(nextcp, ',')); i++)
673
		++nextcp;
674
675
	/* Build an array of that many types. */
676
	if ((av = typelist = reallocarray(NULL, i + 1, sizeof(char *))) == NULL)
677
		err(1, NULL);
678
	av[0] = fslist;
679
	for (i = 1, nextcp = fslist; (nextcp = strchr(nextcp, ',')); i++) {
680
		*nextcp = '\0';
681
		av[i] = ++nextcp;
682
	}
683
	/* Terminate the array. */
684
	av[i] = NULL;
685
}
686
687
char *
688
catopt(char *s0, const char *s1)
689
{
690
	char *cp;
691
692
	if (s0 && *s0) {
693
		if (asprintf(&cp, "%s,%s", s0, s1) == -1)
694
			err(1, NULL);
695
	} else {
696
		if ((cp = strdup(s1)) == NULL)
697
			err(1, NULL);
698
	}
699
700
	free(s0);
701
	return cp;
702
}
703
704
void
705
mangle(char *options, int *argcp, const char **argv, int argcmax)
706
{
707
	char *p, *s;
708
	int argc;
709
710
	argcmax -= 2;
711
	argc = *argcp;
712
	for (s = options; argc <= argcmax && (p = strsep(&s, ",")) != NULL;)
713
		if (*p != '\0') {
714
			if (*p == '-') {
715
				argv[argc++] = p;
716
				p = strchr(p, '=');
717
				if (p) {
718
					*p = '\0';
719
					argv[argc++] = p + 1;
720
				}
721
			} else {
722
				argv[argc++] = "-o";
723
				argv[argc++] = p;
724
			}
725
		}
726
727
	*argcp = argc;
728
}
729
730
__dead void
731
usage(void)
732
{
733
	(void)fprintf(stderr,
734
	    "usage: mount [-AadfNruvw] [-t type]\n"
735
	    "       mount [-dfrsuvw] special | node\n"
736
	    "       mount [-dfruvw] [-o options] [-t type] special node\n");
737
	exit(1);
738
}
739
740
int
741
disklabelcheck(struct fstab *fs)
742
{
743
	char *labelfs;
744
745
	if (strcmp(fs->fs_vfstype, "nfs") != 0 ||
746
	    strpbrk(fs->fs_spec, ":@") == NULL) {
747
		labelfs = readlabelfs(fs->fs_spec, 0);
748
		if (labelfs == NULL ||
749
		    strcmp(labelfs, fs->fs_vfstype) == 0)
750
			return (0);
751
		if (strcmp(fs->fs_vfstype, "ufs") == 0 &&
752
		    strcmp(labelfs, "ffs") == 0) {
753
			warnx("%s: fstab uses outdated type 'ufs' -- fix please",
754
			    fs->fs_spec);
755
			return (0);
756
		}
757
		if (strcmp(fs->fs_vfstype, "mfs") == 0 &&
758
		    strcmp(labelfs, "ffs") == 0)
759
			return (0);
760
		warnx("%s: fstab type %s != disklabel type %s",
761
		    fs->fs_spec, fs->fs_vfstype, labelfs);
762
		return (1);
763
	}
764
	return (0);
765
}