GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/mount/mount.c Lines: 0 342 0.0 %
Date: 2016-12-06 Branches: 0 415 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: mount.c,v 1.66 2016/06/26 19:53:40 tedu 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_WXALLOWED,	0,	"wxallowed",		"wxallowed" },
92
	{ MNT_QUOTA,		0,	"with quotas",		"" },
93
	{ MNT_RDONLY,		0,	"read-only",		"ro" },
94
	{ MNT_ROOTFS,		1,	"root file system",	"" },
95
	{ MNT_SYNCHRONOUS,	0,	"synchronous",		"sync" },
96
	{ MNT_SOFTDEP,		0,	"softdep", 		"softdep" },
97
	{ 0,			0,	"",			"" }
98
};
99
100
int
101
main(int argc, char * const argv[])
102
{
103
	const char *mntonname, *vfstype;
104
	struct fstab *fs;
105
	struct statfs *mntbuf;
106
	FILE *mountdfp;
107
	pid_t pid;
108
	int all, ch, forceall, i, mntsize, rval, new;
109
	char *options, mntpath[PATH_MAX];
110
111
	if (pledge("stdio rpath disklabel proc exec cpath wpath", NULL) == -1)
112
		err(1, "pledge");
113
114
	all = forceall = 0;
115
	options = NULL;
116
	vfstype = "ffs";
117
	while ((ch = getopt(argc, argv, "AadfNo:rswt:uv")) != -1)
118
		switch (ch) {
119
		case 'A':
120
			all = forceall = 1;
121
			break;
122
		case 'a':
123
			all = 1;
124
			break;
125
		case 'd':
126
			debug = 1;
127
			break;
128
		case 'f':
129
			if (!hasopt(options, "force"))
130
				options = catopt(options, "force");
131
			break;
132
		case 'N':
133
			filter = NET_FILTER;
134
			break;
135
		case 'o':
136
			if (*optarg)
137
				options = catopt(options, optarg);
138
			break;
139
		case 'r':
140
			if (!hasopt(options, "ro"))
141
				options = catopt(options, "ro");
142
			break;
143
		case 's':
144
			skip = 1;
145
			break;
146
		case 't':
147
			if (typelist != NULL)
148
				errx(1, "only one -t option may be specified.");
149
			maketypelist(optarg);
150
			vfstype = optarg;
151
			break;
152
		case 'u':
153
			if (!hasopt(options, "update"))
154
				options = catopt(options, "update");
155
			break;
156
		case 'v':
157
			verbose = 1;
158
			break;
159
		case 'w':
160
			if (!hasopt(options, "rw"))
161
				options = catopt(options, "rw");
162
			break;
163
		case '?':
164
		default:
165
			usage();
166
			/* NOTREACHED */
167
		}
168
	argc -= optind;
169
	argv += optind;
170
171
#define	BADTYPE(type)							\
172
	(strcmp(type, FSTAB_RO) &&					\
173
	    strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ))
174
175
	rval = 0;
176
	new = 0;
177
	switch (argc) {
178
	case 0:
179
		if (all)
180
			while ((fs = getfsent()) != NULL) {
181
				if (BADTYPE(fs->fs_type))
182
					continue;
183
				switch (filter) {
184
				case NET_FILTER:
185
					if (!hasopt(fs->fs_mntops, "net"))
186
						continue;
187
					break;
188
				case NONET_FILTER:
189
					if (hasopt(fs->fs_mntops, "net"))
190
						continue;
191
					break;
192
				}
193
				if (!selected(fs->fs_vfstype))
194
					continue;
195
				if (hasopt(fs->fs_mntops, "noauto"))
196
					continue;
197
				if (disklabelcheck(fs))
198
					continue;
199
				if (mountfs(fs->fs_vfstype, fs->fs_spec,
200
				    fs->fs_file, options,
201
				    fs->fs_mntops, !forceall))
202
					rval = 1;
203
				else
204
					++new;
205
			}
206
		else {
207
			if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0)
208
				err(1, "getmntinfo");
209
			for (i = 0; i < mntsize; i++) {
210
				if (!selected(mntbuf[i].f_fstypename))
211
					continue;
212
				prmount(&mntbuf[i]);
213
			}
214
			exit(rval);
215
		}
216
		break;
217
	case 1:
218
		if (typelist != NULL)
219
			usage();
220
221
		if (realpath(*argv, mntpath) == NULL && strpbrk(argv[0], ":@") == NULL)
222
			err(1, "realpath %s", *argv);
223
		if (hasopt(options, "update")) {
224
			if ((mntbuf = getmntpt(mntpath)) == NULL)
225
				errx(1,
226
				    "unknown special file or file system %s.",
227
				    *argv);
228
			if ((mntbuf->f_flags & MNT_ROOTFS) &&
229
			    !strcmp(mntbuf->f_mntfromname, "root_device")) {
230
				/* Lookup fstab for name of root device. */
231
				fs = getfsfile(mntbuf->f_mntonname);
232
				if (fs == NULL)
233
					errx(1,
234
					    "can't find fstab entry for %s.",
235
					    *argv);
236
			} else {
237
				fs = malloc(sizeof(*fs));
238
				if (fs == NULL)
239
					err(1, "malloc");
240
				fs->fs_vfstype = mntbuf->f_fstypename;
241
				fs->fs_spec = mntbuf->f_mntfromname;
242
			}
243
			/*
244
			 * It's an update, ignore the fstab file options.
245
			 * Get the current options, so we can change only
246
			 * the options which given via a command line.
247
			 */
248
			fs->fs_mntops = flags2opts(mntbuf->f_flags);
249
			mntonname = mntbuf->f_mntonname;
250
		} else {
251
			if ((fs = getfsfile(mntpath)) == NULL &&
252
			    (fs = getfsspec(mntpath)) == NULL &&
253
			    (fs = getfsspec(*argv)) == NULL)
254
				errx(1, "can't find fstab entry for %s.",
255
				    *argv);
256
			if (BADTYPE(fs->fs_type))
257
				errx(1, "%s has unknown file system type.",
258
				    *argv);
259
			mntonname = fs->fs_file;
260
		}
261
		rval = mountfs(fs->fs_vfstype, fs->fs_spec,
262
		    mntonname, options, fs->fs_mntops, skip);
263
		break;
264
	case 2:
265
		/*
266
		 * If -t flag has not been specified, and spec contains either
267
		 * a ':' or a '@' then assume that an NFS filesystem is being
268
		 * specified ala Sun.  If not, check the disklabel for a
269
		 * known filesystem type.
270
		 */
271
		if (typelist == NULL) {
272
			if (strpbrk(argv[0], ":@") != NULL)
273
				vfstype = "nfs";
274
			else {
275
				char *labelfs = readlabelfs(argv[0], 0);
276
				if (labelfs != NULL)
277
					vfstype = labelfs;
278
			}
279
		}
280
		rval = mountfs(vfstype,
281
		    argv[0], argv[1], options, NULL, 0);
282
		break;
283
	default:
284
		usage();
285
		/* NOTREACHED */
286
	}
287
288
	/*
289
	 * If the mount was successfully, and done by root, tell mountd the
290
	 * good news.  Pid checks are probably unnecessary, but don't hurt.
291
	 * XXX This should be done from kernel.
292
	 */
293
	if ((rval == 0 || new) && getuid() == 0 &&
294
	    (mountdfp = fopen(_PATH_MOUNTDPID, "r")) != NULL) {
295
		if (fscanf(mountdfp, "%d", &pid) == 1 &&
296
		    pid > 0 && kill(pid, SIGHUP) == -1 && errno != ESRCH)
297
			err(1, "signal mountd");
298
		(void)fclose(mountdfp);
299
	}
300
301
	exit(rval);
302
}
303
304
int
305
hasopt(const char *mntopts, const char *option)
306
{
307
	int found;
308
	char *opt, *optbuf;
309
310
	if (mntopts == NULL)
311
		return (0);
312
	optbuf = strdup(mntopts);
313
	found = 0;
314
	for (opt = optbuf; !found && opt != NULL; strsep(&opt, ","))
315
		found = !strncmp(opt, option, strlen(option));
316
	free(optbuf);
317
	return (found);
318
}
319
320
/*
321
 * Convert mount(2) flags to list of mount(8) options.
322
 */
323
char*
324
flags2opts(u_int32_t flags)
325
{
326
	char	*optlist;
327
	struct opt *p;
328
329
	optlist = NULL;
330
	for (p = optnames; p->o_opt; p++) {
331
		if (flags & p->o_opt && *p->o_optname)
332
			optlist = catopt(optlist, p->o_optname);
333
	}
334
335
	return(optlist);
336
}
337
338
int
339
mountfs(const char *vfstype, const char *spec, const char *name,
340
    const char *options, const char *mntopts, int skipmounted)
341
{
342
	/* List of directories containing mount_xxx subcommands. */
343
	static const char *edirs[] = {
344
		_PATH_SBIN,
345
		_PATH_USRSBIN,
346
		NULL
347
	};
348
	const char **argv, **edir;
349
	struct statfs sf;
350
	pid_t pid;
351
	int argc, i, status, argvsize;
352
	char *optbuf, execname[PATH_MAX], mntpath[PATH_MAX];
353
354
	if (realpath(name, mntpath) == NULL) {
355
		warn("realpath %s", name);
356
		return (1);
357
	}
358
359
	name = mntpath;
360
361
	if (mntopts == NULL)
362
		mntopts = "";
363
364
	if (options == NULL) {
365
		if (*mntopts == '\0')
366
			options = "rw";
367
		else {
368
			options = mntopts;
369
			mntopts = "";
370
		}
371
	}
372
373
	/* options follows after mntopts, so they get priority over mntopts */
374
	optbuf = catopt(strdup(mntopts), options);
375
376
	if (strcmp(name, "/") == 0) {
377
		if (!hasopt(optbuf, "update"))
378
			optbuf = catopt(optbuf, "update");
379
	} else if (skipmounted) {
380
		if (statfs(name, &sf) < 0) {
381
			warn("statfs %s", name);
382
			return (1);
383
		}
384
		/* XXX can't check f_mntfromname, thanks to mfs, etc. */
385
		if (strncmp(name, sf.f_mntonname, MNAMELEN) == 0 &&
386
		    strncmp(vfstype, sf.f_fstypename, MFSNAMELEN) == 0) {
387
			if (verbose) {
388
				printf("%s", sf.f_mntfromname);
389
				if (strncmp(sf.f_mntfromname,
390
				    sf.f_mntfromspec, MNAMELEN) != 0)
391
					printf(" (%s)", sf.f_mntfromspec);
392
				printf(" on %s type %.*s: %s\n",
393
				    sf.f_mntonname,
394
				    MFSNAMELEN, sf.f_fstypename,
395
				    "already mounted");
396
			}
397
			return (0);
398
		}
399
	}
400
401
	argvsize = 64;
402
	if((argv = reallocarray(NULL, argvsize, sizeof(char *))) == NULL)
403
		err(1, "malloc");
404
	argc = 0;
405
	argv[argc++] = NULL;	/* this should be a full path name */
406
	mangle(optbuf, &argc, argv, argvsize - 4);
407
	argv[argc++] = spec;
408
	argv[argc++] = name;
409
	argv[argc] = NULL;
410
411
	if (debug) {
412
		(void)printf("exec: mount_%s", vfstype);
413
		for (i = 1; i < argc; i++)
414
			(void)printf(" %s", argv[i]);
415
		(void)printf("\n");
416
		free(optbuf);
417
		free(argv);
418
		return (0);
419
	}
420
421
	switch ((pid = fork())) {
422
	case -1:				/* Error. */
423
		warn("fork");
424
		free(optbuf);
425
		free(argv);
426
		return (1);
427
	case 0:					/* Child. */
428
		/* Go find an executable. */
429
		edir = edirs;
430
		do {
431
			(void)snprintf(execname,
432
			    sizeof(execname), "%s/mount_%s", *edir, vfstype);
433
			argv[0] = execname;
434
			execv(execname, (char * const *)argv);
435
			if (errno != ENOENT)
436
				warn("exec %s for %s", execname, name);
437
		} while (*++edir != NULL);
438
439
		if (errno == ENOENT)
440
			warn("no mount helper program found for %s", vfstype);
441
		_exit(1);
442
		/* NOTREACHED */
443
	default:				/* Parent. */
444
		free(optbuf);
445
		free(argv);
446
447
		if (waitpid(pid, &status, 0) < 0) {
448
			warn("waitpid");
449
			return (1);
450
		}
451
452
		if (WIFEXITED(status)) {
453
			if (WEXITSTATUS(status) != 0)
454
				return (WEXITSTATUS(status));
455
		} else if (WIFSIGNALED(status)) {
456
			warnx("%s: %s", name, strsignal(WTERMSIG(status)));
457
			return (1);
458
		}
459
460
		if (verbose) {
461
			if (statfs(name, &sf) < 0) {
462
				warn("statfs %s", name);
463
				return (1);
464
			}
465
			prmount(&sf);
466
		}
467
		break;
468
	}
469
470
	return (0);
471
}
472
473
void
474
prmount(struct statfs *sf)
475
{
476
	int flags;
477
	struct opt *o;
478
	int f = 0;
479
480
	printf("%s", sf->f_mntfromname);
481
	if (verbose &&
482
	    strncmp(sf->f_mntfromname, sf->f_mntfromspec, MNAMELEN) != 0)
483
		printf(" (%s)", sf->f_mntfromspec);
484
	printf(" on %s type %.*s", sf->f_mntonname,
485
	    MFSNAMELEN, sf->f_fstypename);
486
487
	flags = sf->f_flags & MNT_VISFLAGMASK;
488
	if (verbose && !(flags & MNT_RDONLY))
489
		(void)printf("%s%s", !f++ ? " (" : ", ", "rw");
490
	for (o = optnames; flags && o->o_opt; o++)
491
		if (flags & o->o_opt) {
492
			if (!o->o_silent)
493
				(void)printf("%s%s", !f++ ? " (" : ", ",
494
				    o->o_name);
495
			flags &= ~o->o_opt;
496
		}
497
	if (flags)
498
		(void)printf("%sunknown flag%s %#x", !f++ ? " (" : ", ",
499
		    flags & (flags - 1) ? "s" : "", flags);
500
501
502
	if (verbose) {
503
		char buf[26];
504
		time_t t = sf->f_ctime;
505
506
		ctime_r(&t, buf);
507
		buf[24] = '\0';
508
		printf(", ctime=%s", buf);
509
	}
510
511
	/*
512
	 * Filesystem-specific options
513
	 * We only print the "interesting" values unless in verbose
514
	 * mode in order to keep the signal/noise ratio high.
515
	 */
516
	if (strcmp(sf->f_fstypename, MOUNT_NFS) == 0) {
517
		struct protoent *pr;
518
		struct nfs_args *nfs_args = &sf->mount_info.nfs_args;
519
520
		(void)printf("%s%s", !f++ ? " (" : ", ",
521
		    (nfs_args->flags & NFSMNT_NFSV3) ? "v3" : "v2");
522
		if (nfs_args->proto && (pr = getprotobynumber(nfs_args->proto)))
523
			(void)printf("%s%s", !f++ ? " (" : ", ", pr->p_name);
524
		else
525
			(void)printf("%s%s", !f++ ? " (" : ", ",
526
			    (nfs_args->sotype == SOCK_DGRAM) ? "udp" : "tcp");
527
		if (nfs_args->flags & NFSMNT_SOFT)
528
			(void)printf("%s%s", !f++ ? " (" : ", ", "soft");
529
		else if (verbose)
530
			(void)printf("%s%s", !f++ ? " (" : ", ", "hard");
531
		if (nfs_args->flags & NFSMNT_INT)
532
			(void)printf("%s%s", !f++ ? " (" : ", ", "intr");
533
		if (nfs_args->flags & NFSMNT_NOCONN)
534
			(void)printf("%s%s", !f++ ? " (" : ", ", "noconn");
535
		if (nfs_args->flags & NFSMNT_RDIRPLUS)
536
			(void)printf("%s%s", !f++ ? " (" : ", ", "rdirplus");
537
		if (verbose || nfs_args->wsize != NFS_WSIZE)
538
			(void)printf("%s%s=%d", !f++ ? " (" : ", ",
539
			    "wsize", nfs_args->wsize);
540
		if (verbose || nfs_args->rsize != NFS_RSIZE)
541
			(void)printf("%s%s=%d", !f++ ? " (" : ", ",
542
			    "rsize", nfs_args->rsize);
543
		if (verbose || nfs_args->readdirsize != NFS_READDIRSIZE)
544
			(void)printf("%s%s=%d", !f++ ? " (" : ", ",
545
			    "rdirsize", nfs_args->readdirsize);
546
		if (verbose || nfs_args->timeo != 10) /* XXX */
547
			(void)printf("%s%s=%d", !f++ ? " (" : ", ",
548
			    "timeo", nfs_args->timeo);
549
		if (verbose || nfs_args->retrans != NFS_RETRANS)
550
			(void)printf("%s%s=%d", !f++ ? " (" : ", ",
551
			    "retrans", nfs_args->retrans);
552
		if (verbose || nfs_args->maxgrouplist != NFS_MAXGRPS)
553
			(void)printf("%s%s=%d", !f++ ? " (" : ", ",
554
			    "maxgrouplist", nfs_args->maxgrouplist);
555
		if (verbose || nfs_args->readahead != NFS_DEFRAHEAD)
556
			(void)printf("%s%s=%d", !f++ ? " (" : ", ",
557
			    "readahead", nfs_args->readahead);
558
		if (verbose) {
559
			(void)printf("%s%s=%d", !f++ ? " (" : ", ",
560
			    "acregmin", nfs_args->acregmin);
561
			(void)printf(", %s=%d",
562
			    "acregmax", nfs_args->acregmax);
563
			(void)printf(", %s=%d",
564
			    "acdirmin", nfs_args->acdirmin);
565
			(void)printf(", %s=%d",
566
			    "acdirmax", nfs_args->acdirmax);
567
		}
568
	} else if (strcmp(sf->f_fstypename, MOUNT_MFS) == 0) {
569
		int headerlen;
570
		long blocksize;
571
		char *header;
572
573
		header = getbsize(&headerlen, &blocksize);
574
		(void)printf("%s%s=%lu %s", !f++ ? " (" : ", ",
575
		    "size", sf->mount_info.mfs_args.size / blocksize, header);
576
	} else if (strcmp(sf->f_fstypename, MOUNT_MSDOS) == 0) {
577
		struct msdosfs_args *msdosfs_args = &sf->mount_info.msdosfs_args;
578
579
		if (verbose || msdosfs_args->uid || msdosfs_args->gid)
580
			(void)printf("%s%s=%u, %s=%u", !f++ ? " (" : ", ",
581
			    "uid", msdosfs_args->uid, "gid", msdosfs_args->gid);
582
		if (verbose || msdosfs_args->mask != 0755)
583
			(void)printf("%s%s=0%o", !f++ ? " (" : ", ",
584
			    "mask", msdosfs_args->mask);
585
		if (msdosfs_args->flags & MSDOSFSMNT_SHORTNAME)
586
			(void)printf("%s%s", !f++ ? " (" : ", ", "short");
587
		if (msdosfs_args->flags & MSDOSFSMNT_LONGNAME)
588
			(void)printf("%s%s", !f++ ? " (" : ", ", "long");
589
		if (msdosfs_args->flags & MSDOSFSMNT_NOWIN95)
590
			(void)printf("%s%s", !f++ ? " (" : ", ", "nowin95");
591
	} else if (strcmp(sf->f_fstypename, MOUNT_CD9660) == 0) {
592
		struct iso_args *iso_args = &sf->mount_info.iso_args;
593
594
		if (iso_args->flags & ISOFSMNT_NORRIP)
595
			(void)printf("%s%s", !f++ ? " (" : ", ", "norrip");
596
		if (iso_args->flags & ISOFSMNT_GENS)
597
			(void)printf("%s%s", !f++ ? " (" : ", ", "gens");
598
		if (iso_args->flags & ISOFSMNT_EXTATT)
599
			(void)printf("%s%s", !f++ ? " (" : ", ", "extatt");
600
	} else if (strcmp(sf->f_fstypename, MOUNT_TMPFS) == 0) {
601
		struct tmpfs_args *tmpfs_args = &sf->mount_info.tmpfs_args;
602
603
		if (verbose || tmpfs_args->ta_root_uid || tmpfs_args->ta_root_gid)
604
			(void)printf("%s%s=%u, %s=%u", !f++ ? " (" : ", ",
605
			    "uid", tmpfs_args->ta_root_uid, "gid", tmpfs_args->ta_root_gid);
606
		if (verbose || tmpfs_args->ta_root_mode != 040755)
607
			(void)printf("%s%s=%04o", !f++ ? " (" : ", ",
608
			    "mode", tmpfs_args->ta_root_mode & 07777);
609
		if (verbose || tmpfs_args->ta_size_max)
610
			(void)printf("%s%s=%lu", !f++ ? " (" : ", ",
611
			    "size", (unsigned long)tmpfs_args->ta_size_max);
612
		if (verbose || tmpfs_args->ta_nodes_max)
613
			(void)printf("%s%s=%lu", !f++ ? " (" : ", ",
614
			    "inodes", (unsigned long)tmpfs_args->ta_nodes_max);
615
	}
616
	(void)printf(f ? ")\n" : "\n");
617
}
618
619
struct statfs *
620
getmntpt(const char *name)
621
{
622
	struct statfs *mntbuf;
623
	int i, mntsize;
624
625
	mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
626
	for (i = 0; i < mntsize; i++)
627
		if (strcmp(mntbuf[i].f_mntfromname, name) == 0 ||
628
		    strcmp(mntbuf[i].f_mntonname, name) == 0)
629
			return (&mntbuf[i]);
630
	return (NULL);
631
}
632
633
static enum { IN_LIST, NOT_IN_LIST } which;
634
635
int
636
selected(const char *type)
637
{
638
	char **av;
639
640
	/* If no type specified, it's always selected. */
641
	if (typelist == NULL)
642
		return (1);
643
	for (av = typelist; *av != NULL; ++av)
644
		if (!strncmp(type, *av, MFSNAMELEN))
645
			return (which == IN_LIST ? 1 : 0);
646
	return (which == IN_LIST ? 0 : 1);
647
}
648
649
void
650
maketypelist(char *fslist)
651
{
652
	int i;
653
	char *nextcp, **av;
654
655
	if ((fslist == NULL) || (fslist[0] == '\0'))
656
		errx(1, "empty type list");
657
658
	/*
659
	 * XXX
660
	 * Note: the syntax is "noxxx,yyy" for no xxx's and
661
	 * no yyy's, not the more intuitive "noxxx,noyyy".
662
	 */
663
	if (fslist[0] == 'n' && fslist[1] == 'o') {
664
		fslist += 2;
665
		which = NOT_IN_LIST;
666
	} else
667
		which = IN_LIST;
668
669
	/* Count the number of types. */
670
	for (i = 1, nextcp = fslist; (nextcp = strchr(nextcp, ',')); i++)
671
		++nextcp;
672
673
	/* Build an array of that many types. */
674
	if ((av = typelist = reallocarray(NULL, i + 1, sizeof(char *))) == NULL)
675
		err(1, "malloc");
676
	av[0] = fslist;
677
	for (i = 1, nextcp = fslist; (nextcp = strchr(nextcp, ',')); i++) {
678
		*nextcp = '\0';
679
		av[i] = ++nextcp;
680
	}
681
	/* Terminate the array. */
682
	av[i] = NULL;
683
}
684
685
char *
686
catopt(char *s0, const char *s1)
687
{
688
	size_t i;
689
	char *cp;
690
691
	if (s0 && *s0) {
692
		i = strlen(s0) + strlen(s1) + 1 + 1;
693
		if ((cp = malloc(i)) == NULL)
694
			err(1, NULL);
695
		(void)snprintf(cp, i, "%s,%s", s0, s1);
696
	} else
697
		cp = strdup(s1);
698
699
	free(s0);
700
	return (cp);
701
}
702
703
void
704
mangle(char *options, int *argcp, const char **argv, int argcmax)
705
{
706
	char *p, *s;
707
	int argc;
708
709
	argcmax -= 2;
710
	argc = *argcp;
711
	for (s = options; argc <= argcmax && (p = strsep(&s, ",")) != NULL;)
712
		if (*p != '\0') {
713
			if (*p == '-') {
714
				argv[argc++] = p;
715
				p = strchr(p, '=');
716
				if (p) {
717
					*p = '\0';
718
					argv[argc++] = p + 1;
719
				}
720
			} else {
721
				argv[argc++] = "-o";
722
				argv[argc++] = p;
723
			}
724
		}
725
726
	*argcp = argc;
727
}
728
729
void
730
usage(void)
731
{
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
}
766