Bug Summary

File:src/sbin/mount/mount.c
Warning:line 222, column 19
Potential leak of memory pointed to by 'options'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name mount.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sbin/mount/obj -resource-dir /usr/local/llvm16/lib/clang/16 -internal-isystem /usr/local/llvm16/lib/clang/16/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/sbin/mount/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fcf-protection=branch -fno-jump-tables -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/scan/2024-01-11-140451-98009-1 -x c /usr/src/sbin/mount/mount.c
1/* $OpenBSD: mount.c,v 1.77 2023/07/23 23:21:19 kn 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(*__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
56int debug, verbose, skip;
57char **typelist = NULL((void *)0);
58enum { NONET_FILTER, NET_FILTER } filter = NONET_FILTER;
59
60int selected(const char *);
61char *catopt(char *, const char *);
62char *flags2opts(u_int32_t);
63struct statfs
64 *getmntpt(const char *);
65int hasopt(const char *, const char *);
66void maketypelist(char *);
67void mangle(char *, int *, const char **, int);
68int mountfs(const char *, const char *, const char *, const char *,
69 const char *, int);
70void prmount(struct statfs *);
71int disklabelcheck(struct fstab *);
72__dead__attribute__((__noreturn__)) void usage(void);
73
74/* Map from mount options to printable formats. */
75static struct opt {
76 int o_opt;
77 int o_silent;
78 const char *o_name;
79 const char *o_optname;
80} optnames[] = {
81 { MNT_ASYNC0x00000040, 0, "asynchronous", "async" },
82 { MNT_DEFEXPORTED0x00000200, 1, "exported to the world", "" },
83 { MNT_EXPORTED0x00000100, 0, "NFS exported", "" },
84 { MNT_EXPORTANON0x00000400, 1, "anon uid mapping", "" },
85 { MNT_EXRDONLY0x00000080, 1, "exported read-only", "" },
86 { MNT_LOCAL0x00001000, 0, "local", "" },
87 { MNT_NOATIME0x00008000, 0, "noatime", "noatime" },
88 { MNT_NODEV0x00000010, 0, "nodev", "nodev" },
89 { MNT_NOEXEC0x00000004, 0, "noexec", "noexec" },
90 { MNT_NOSUID0x00000008, 0, "nosuid", "nosuid" },
91 { MNT_NOPERM0x00000020, 0, "noperm", "noperm" },
92 { MNT_WXALLOWED0x00000800, 0, "wxallowed", "wxallowed" },
93 { MNT_QUOTA0x00002000, 0, "with quotas", "" },
94 { MNT_RDONLY0x00000001, 0, "read-only", "ro" },
95 { MNT_ROOTFS0x00004000, 1, "root file system", "" },
96 { MNT_SYNCHRONOUS0x00000002, 0, "synchronous", "sync" },
97 { MNT_SOFTDEP0x04000000, 0, "softdep", "softdep" },
98 { 0, 0, "", "" }
99};
100
101int
102main(int argc, char * const argv[])
103{
104 const char *mntonname, *vfstype;
105 struct fstab *fs;
106 struct statfs *mntbuf;
107 FILE *mountdfp;
108 pid_t pid;
109 int all, ch, forceall, i, mntsize, rval, new;
110 char *options, mntpath[PATH_MAX1024];
111
112 all = forceall = 0;
113 options = NULL((void *)0);
114 vfstype = "ffs";
115 while ((ch = getopt(argc, argv, "AadfNo:rswt:uv")) != -1)
1
Assuming the condition is true
2
Loop condition is true. Entering loop body
10
Execution continues on line 115
11
Assuming the condition is false
12
Loop condition is false. Execution continues on line 164
116 switch (ch) {
3
Control jumps to 'case 117:' at line 150
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((void *)0))
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"))
4
Taking true branch
152 options = catopt(options, "update");
5
Calling 'catopt'
9
Returned allocated memory
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 default:
162 usage();
163 }
164 argc -= optind;
165 argv += optind;
166
167 if (typelist
12.1
'typelist' is equal to NULL
== NULL((void *)0) && argc == 2) {
13
Assuming 'argc' is not equal to 2
14
Taking false branch
168 /*
169 * If -t flag has not been specified, and spec contains either
170 * a ':' or a '@' then assume that an NFS filesystem is being
171 * specified ala Sun. If not, check the disklabel for a
172 * known filesystem type.
173 */
174 if (strpbrk(argv[0], ":@") != NULL((void *)0))
175 vfstype = "nfs";
176 else {
177 char *labelfs = readlabelfs(argv[0], 0);
178 if (labelfs != NULL((void *)0))
179 vfstype = labelfs;
180 }
181 }
182
183 if (pledge("stdio rpath disklabel proc exec", NULL((void *)0)) == -1)
15
Assuming the condition is false
16
Taking false branch
184 err(1, "pledge");
185
186#define BADTYPE(type)(strcmp(type, "ro") && strcmp(type, "rw") && strcmp
(type, "rq"))
\
187 (strcmp(type, FSTAB_RO"ro") && \
188 strcmp(type, FSTAB_RW"rw") && strcmp(type, FSTAB_RQ"rq"))
189
190 rval = 0;
191 new = 0;
192 switch (argc) {
17
Control jumps to 'case 0:' at line 193
193 case 0:
194 if (all
17.1
'all' is 0
)
18
Taking false branch
195 while ((fs = getfsent()) != NULL((void *)0)) {
196 if (BADTYPE(fs->fs_type)(strcmp(fs->fs_type, "ro") && strcmp(fs->fs_type
, "rw") && strcmp(fs->fs_type, "rq"))
)
197 continue;
198 switch (filter) {
199 case NET_FILTER:
200 if (!hasopt(fs->fs_mntops, "net"))
201 continue;
202 break;
203 case NONET_FILTER:
204 if (hasopt(fs->fs_mntops, "net"))
205 continue;
206 break;
207 }
208 if (!selected(fs->fs_vfstype))
209 continue;
210 if (hasopt(fs->fs_mntops, "noauto"))
211 continue;
212 if (disklabelcheck(fs))
213 continue;
214 if (mountfs(fs->fs_vfstype, fs->fs_spec,
215 fs->fs_file, options,
216 fs->fs_mntops, !forceall))
217 rval = 1;
218 else
219 ++new;
220 }
221 else {
222 if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT2)) == 0)
19
Potential leak of memory pointed to by 'options'
223 err(1, "getmntinfo");
224 for (i = 0; i < mntsize; i++) {
225 if (!selected(mntbuf[i].f_fstypename))
226 continue;
227 prmount(&mntbuf[i]);
228 }
229 return (rval);
230 }
231 break;
232 case 1:
233 if (typelist != NULL((void *)0))
234 usage();
235
236 if (realpath(*argv, mntpath) == NULL((void *)0))
237 strlcpy(mntpath, *argv, sizeof(mntpath));
238 if (hasopt(options, "update")) {
239 if ((mntbuf = getmntpt(mntpath)) == NULL((void *)0))
240 errx(1,
241 "unknown special file or file system %s.",
242 mntpath);
243 if ((mntbuf->f_flags & MNT_ROOTFS0x00004000) &&
244 !strcmp(mntbuf->f_mntfromname, "root_device")) {
245 /* Lookup fstab for name of root device. */
246 fs = getfsfile(mntbuf->f_mntonname);
247 if (fs == NULL((void *)0))
248 errx(1,
249 "can't find fstab entry for %s.",
250 mntpath);
251 } else {
252 if ((fs = malloc(sizeof(*fs))) == NULL((void *)0))
253 err(1, NULL((void *)0));
254 fs->fs_vfstype = mntbuf->f_fstypename;
255 fs->fs_spec = mntbuf->f_mntfromname;
256 }
257 /*
258 * It's an update, ignore the fstab file options.
259 * Get the current options, so we can change only
260 * the options which given via a command line.
261 */
262 fs->fs_mntops = flags2opts(mntbuf->f_flags);
263 mntonname = mntbuf->f_mntonname;
264 } else {
265 if ((fs = getfsfile(mntpath)) == NULL((void *)0) &&
266 (fs = getfsspec(mntpath)) == NULL((void *)0))
267 errx(1, "can't find fstab entry for %s.",
268 mntpath);
269 if (BADTYPE(fs->fs_type)(strcmp(fs->fs_type, "ro") && strcmp(fs->fs_type
, "rw") && strcmp(fs->fs_type, "rq"))
)
270 errx(1, "%s has unknown file system type.",
271 mntpath);
272 mntonname = fs->fs_file;
273 }
274 rval = mountfs(fs->fs_vfstype, fs->fs_spec,
275 mntonname, options, fs->fs_mntops, skip);
276 break;
277 case 2:
278 rval = mountfs(vfstype, argv[0], argv[1], options, NULL((void *)0), skip);
279 break;
280 default:
281 usage();
282 }
283
284 /*
285 * If the mount was successful and done by root, tell mountd the
286 * good news. Pid checks are probably unnecessary, but don't hurt.
287 * XXX This should be done from kernel.
288 */
289 if ((rval == 0 || new) && getuid() == 0 &&
290 (mountdfp = fopen(_PATH_MOUNTDPID"/var/run/mountd.pid", "r")) != NULL((void *)0)) {
291 if (fscanf(mountdfp, "%d", &pid) == 1 &&
292 pid > 0 && kill(pid, SIGHUP1) == -1 && errno(*__errno()) != ESRCH3)
293 err(1, "signal mountd");
294 (void)fclose(mountdfp);
295 }
296
297 return (rval);
298}
299
300int
301hasopt(const char *mntopts, const char *option)
302{
303 int found;
304 char *opt, *optbuf;
305
306 if (mntopts == NULL((void *)0))
307 return (0);
308 if ((optbuf = strdup(mntopts)) == NULL((void *)0))
309 err(1, NULL((void *)0));
310 found = 0;
311 for (opt = optbuf; !found && opt != NULL((void *)0); strsep(&opt, ","))
312 found = !strncmp(opt, option, strlen(option));
313 free(optbuf);
314 return (found);
315}
316
317/*
318 * Convert mount(2) flags to list of mount(8) options.
319 */
320char*
321flags2opts(u_int32_t flags)
322{
323 char *optlist;
324 struct opt *p;
325
326 optlist = NULL((void *)0);
327 for (p = optnames; p->o_opt; p++) {
328 if (flags & p->o_opt && *p->o_optname)
329 optlist = catopt(optlist, p->o_optname);
330 }
331
332 return(optlist);
333}
334
335int
336mountfs(const char *vfstype, const char *spec, const char *name,
337 const char *options, const char *mntopts, int skipmounted)
338{
339 char *cp;
340
341 /* List of directories containing mount_xxx subcommands. */
342 static const char *edirs[] = {
343 _PATH_SBIN"/sbin",
344 _PATH_USRSBIN"/usr/sbin",
345 NULL((void *)0)
346 };
347 const char **argv, **edir;
348 struct statfs sf;
349 pid_t pid;
350 int argc, i, status, argvsize;
351 char *optbuf, execname[PATH_MAX1024], mntpath[PATH_MAX1024];
352
353 if (realpath(name, mntpath) == NULL((void *)0)) {
354 warn("realpath %s", name);
355 return (1);
356 }
357
358 name = mntpath;
359
360 if (mntopts == NULL((void *)0))
361 mntopts = "";
362
363 if (options == NULL((void *)0)) {
364 if (*mntopts == '\0')
365 options = "rw";
366 else {
367 options = mntopts;
368 mntopts = "";
369 }
370 }
371
372 /* options follows after mntopts, so they get priority over mntopts */
373 if ((cp = strdup(mntopts)) == NULL((void *)0))
374 err(1, NULL((void *)0));
375 optbuf = catopt(cp, options);
376
377 if (strcmp(name, "/") == 0) {
378 if (!hasopt(optbuf, "update"))
379 optbuf = catopt(optbuf, "update");
380 } else if (skipmounted) {
381 if (statfs(name, &sf) == -1) {
382 warn("statfs %s", name);
383 return (1);
384 }
385 /* XXX can't check f_mntfromname, thanks to mfs, etc. */
386 if (strncmp(name, sf.f_mntonname, MNAMELEN90) == 0 &&
387 strncmp(vfstype, sf.f_fstypename, MFSNAMELEN16) == 0) {
388 if (verbose) {
389 printf("%s", sf.f_mntfromname);
390 if (strncmp(sf.f_mntfromname,
391 sf.f_mntfromspec, MNAMELEN90) != 0)
392 printf(" (%s)", sf.f_mntfromspec);
393 printf(" on %s type %.*s: %s\n",
394 sf.f_mntonname,
395 MFSNAMELEN16, sf.f_fstypename,
396 "already mounted");
397 }
398 return (0);
399 }
400 }
401
402 argvsize = 64;
403 if((argv = reallocarray(NULL((void *)0), argvsize, sizeof(char *))) == NULL((void *)0))
404 err(1, NULL((void *)0));
405 argc = 0;
406 argv[argc++] = NULL((void *)0); /* this should be a full path name */
407 mangle(optbuf, &argc, argv, argvsize - 4);
408 argv[argc++] = spec;
409 argv[argc++] = name;
410 argv[argc] = NULL((void *)0);
411
412 if (debug) {
413 (void)printf("exec: mount_%s", vfstype);
414 for (i = 1; i < argc; i++)
415 (void)printf(" %s", argv[i]);
416 (void)printf("\n");
417 free(optbuf);
418 free(argv);
419 return (0);
420 }
421
422 switch ((pid = fork())) {
423 case -1: /* Error. */
424 warn("fork");
425 free(optbuf);
426 free(argv);
427 return (1);
428 case 0: /* Child. */
429 /* Go find an executable. */
430 edir = edirs;
431 do {
432 (void)snprintf(execname,
433 sizeof(execname), "%s/mount_%s", *edir, vfstype);
434 argv[0] = execname;
435 execv(execname, (char * const *)argv);
436 if (errno(*__errno()) != ENOENT2)
437 warn("exec %s for %s", execname, name);
438 } while (*++edir != NULL((void *)0));
439
440 if (errno(*__errno()) == ENOENT2)
441 warn("no mount helper program found for %s", vfstype);
442 _exit(1);
443 default: /* Parent. */
444 free(optbuf);
445 free(argv);
446
447 if (waitpid(pid, &status, 0) == -1) {
448 warn("waitpid");
449 return (1);
450 }
451
452 if (WIFEXITED(status)(((status) & 0177) == 0)) {
453 if (WEXITSTATUS(status)(int)(((unsigned)(status) >> 8) & 0xff) != 0)
454 return (WEXITSTATUS(status)(int)(((unsigned)(status) >> 8) & 0xff));
455 } else if (WIFSIGNALED(status)(((status) & 0177) != 0177 && ((status) & 0177
) != 0)
) {
456 warnx("%s: %s", name, strsignal(WTERMSIG(status)(((status) & 0177))));
457 return (1);
458 }
459
460 if (verbose) {
461 if (statfs(name, &sf) == -1) {
462 warn("statfs %s", name);
463 return (1);
464 }
465 prmount(&sf);
466 }
467 break;
468 }
469
470 return (0);
471}
472
473void
474prmount(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, MNAMELEN90) != 0)
483 printf(" (%s)", sf->f_mntfromspec);
484 printf(" on %s type %.*s", sf->f_mntonname,
485 MFSNAMELEN16, sf->f_fstypename);
486
487 flags = sf->f_flags & MNT_VISFLAGMASK0x0400ffff;
488 if (verbose && !(flags & MNT_RDONLY0x00000001))
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"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_NFSV30x00000200) ? "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_DGRAM2) ? "udp" : "tcp");
527 if (nfs_args->flags & NFSMNT_SOFT0x00000001)
528 (void)printf("%s%s", !f++ ? " (" : ", ", "soft");
529 else if (verbose)
530 (void)printf("%s%s", !f++ ? " (" : ", ", "hard");
531 if (nfs_args->flags & NFSMNT_INT0x00000040)
532 (void)printf("%s%s", !f++ ? " (" : ", ", "intr");
533 if (nfs_args->flags & NFSMNT_NOCONN0x00000080)
534 (void)printf("%s%s", !f++ ? " (" : ", ", "noconn");
535 if (nfs_args->flags & NFSMNT_RDIRPLUS0x00010000)
536 (void)printf("%s%s", !f++ ? " (" : ", ", "rdirplus");
537 if (verbose || nfs_args->wsize != NFS_WSIZE8192)
538 (void)printf("%s%s=%d", !f++ ? " (" : ", ",
539 "wsize", nfs_args->wsize);
540 if (verbose || nfs_args->rsize != NFS_RSIZE8192)
541 (void)printf("%s%s=%d", !f++ ? " (" : ", ",
542 "rsize", nfs_args->rsize);
543 if (verbose || nfs_args->readdirsize != NFS_READDIRSIZE8192)
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_RETRANS10)
550 (void)printf("%s%s=%d", !f++ ? " (" : ", ",
551 "retrans", nfs_args->retrans);
552 if (verbose || nfs_args->maxgrouplist != NFS_MAXGRPS16)
553 (void)printf("%s%s=%d", !f++ ? " (" : ", ",
554 "maxgrouplist", nfs_args->maxgrouplist);
555 if (verbose || nfs_args->readahead != NFS_DEFRAHEAD1)
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#ifndef SMALL
569 } else if (strcmp(sf->f_fstypename, MOUNT_MFS"mfs") == 0) {
570 int headerlen;
571 long blocksize;
572 char *header;
573
574 header = getbsize(&headerlen, &blocksize);
575 (void)printf("%s%s=%lu %s", !f++ ? " (" : ", ",
576 "size", sf->mount_info.mfs_args.size / blocksize, header);
577#endif /* SMALL */
578 } else if (strcmp(sf->f_fstypename, MOUNT_MSDOS"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_SHORTNAME0x01)
588 (void)printf("%s%s", !f++ ? " (" : ", ", "short");
589 if (msdosfs_args->flags & MSDOSFSMNT_LONGNAME0x02)
590 (void)printf("%s%s", !f++ ? " (" : ", ", "long");
591 if (msdosfs_args->flags & MSDOSFSMNT_NOWIN950x04)
592 (void)printf("%s%s", !f++ ? " (" : ", ", "nowin95");
593 } else if (strcmp(sf->f_fstypename, MOUNT_CD9660"cd9660") == 0) {
594 struct iso_args *iso_args = &sf->mount_info.iso_args;
595
596 if (iso_args->flags & ISOFSMNT_NORRIP0x00000001)
597 (void)printf("%s%s", !f++ ? " (" : ", ", "norrip");
598 if (iso_args->flags & ISOFSMNT_GENS0x00000002)
599 (void)printf("%s%s", !f++ ? " (" : ", ", "gens");
600 if (iso_args->flags & ISOFSMNT_EXTATT0x00000004)
601 (void)printf("%s%s", !f++ ? " (" : ", ", "extatt");
602#ifndef SMALL
603 } else if (strcmp(sf->f_fstypename, MOUNT_TMPFS"tmpfs") == 0) {
604 struct tmpfs_args *tmpfs_args = &sf->mount_info.tmpfs_args;
605
606 if (verbose || tmpfs_args->ta_root_uid || tmpfs_args->ta_root_gid)
607 (void)printf("%s%s=%u, %s=%u", !f++ ? " (" : ", ",
608 "uid", tmpfs_args->ta_root_uid, "gid", tmpfs_args->ta_root_gid);
609 if (verbose || tmpfs_args->ta_root_mode != 040755)
610 (void)printf("%s%s=%04o", !f++ ? " (" : ", ",
611 "mode", tmpfs_args->ta_root_mode & 07777);
612 if (verbose || tmpfs_args->ta_size_max)
613 (void)printf("%s%s=%lu", !f++ ? " (" : ", ",
614 "size", (unsigned long)tmpfs_args->ta_size_max);
615 if (verbose || tmpfs_args->ta_nodes_max)
616 (void)printf("%s%s=%lu", !f++ ? " (" : ", ",
617 "inodes", (unsigned long)tmpfs_args->ta_nodes_max);
618#endif /* SMALL */
619 }
620 (void)printf(f ? ")\n" : "\n");
621}
622
623struct statfs *
624getmntpt(const char *name)
625{
626 struct statfs *mntbuf;
627 int i, mntsize;
628
629 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT2);
630 for (i = 0; i < mntsize; i++)
631 if (strcmp(mntbuf[i].f_mntfromname, name) == 0 ||
632 strcmp(mntbuf[i].f_mntonname, name) == 0)
633 return (&mntbuf[i]);
634 return (NULL((void *)0));
635}
636
637static enum { IN_LIST, NOT_IN_LIST } which;
638
639int
640selected(const char *type)
641{
642 char **av;
643
644 /* If no type specified, it's always selected. */
645 if (typelist == NULL((void *)0))
646 return (1);
647 for (av = typelist; *av != NULL((void *)0); ++av)
648 if (!strncmp(type, *av, MFSNAMELEN16))
649 return (which == IN_LIST ? 1 : 0);
650 return (which == IN_LIST ? 0 : 1);
651}
652
653void
654maketypelist(char *fslist)
655{
656 int i;
657 char *nextcp, **av;
658
659 if ((fslist == NULL((void *)0)) || (fslist[0] == '\0'))
660 errx(1, "empty type list");
661
662 /*
663 * XXX
664 * Note: the syntax is "noxxx,yyy" for no xxx's and
665 * no yyy's, not the more intuitive "noxxx,noyyy".
666 */
667 if (fslist[0] == 'n' && fslist[1] == 'o') {
668 fslist += 2;
669 which = NOT_IN_LIST;
670 } else
671 which = IN_LIST;
672
673 /* Count the number of types. */
674 for (i = 1, nextcp = fslist; (nextcp = strchr(nextcp, ',')); i++)
675 ++nextcp;
676
677 /* Build an array of that many types. */
678 if ((av = typelist = reallocarray(NULL((void *)0), i + 1, sizeof(char *))) == NULL((void *)0))
679 err(1, NULL((void *)0));
680 av[0] = fslist;
681 for (i = 1, nextcp = fslist; (nextcp = strchr(nextcp, ',')); i++) {
682 *nextcp = '\0';
683 av[i] = ++nextcp;
684 }
685 /* Terminate the array. */
686 av[i] = NULL((void *)0);
687}
688
689char *
690catopt(char *s0, const char *s1)
691{
692 char *cp;
693
694 if (s0
5.1
's0' is null
&& *s0) {
695 if (asprintf(&cp, "%s,%s", s0, s1) == -1)
696 err(1, NULL((void *)0));
697 } else {
698 if ((cp = strdup(s1)) == NULL((void *)0))
6
Memory is allocated
7
Assuming the condition is false
8
Taking false branch
699 err(1, NULL((void *)0));
700 }
701
702 free(s0);
703 return cp;
704}
705
706void
707mangle(char *options, int *argcp, const char **argv, int argcmax)
708{
709 char *p, *s;
710 int argc;
711
712 argcmax -= 2;
713 argc = *argcp;
714 for (s = options; argc <= argcmax && (p = strsep(&s, ",")) != NULL((void *)0);)
715 if (*p != '\0') {
716 if (*p == '-') {
717 argv[argc++] = p;
718 p = strchr(p, '=');
719 if (p) {
720 *p = '\0';
721 argv[argc++] = p + 1;
722 }
723 } else {
724 argv[argc++] = "-o";
725 argv[argc++] = p;
726 }
727 }
728
729 *argcp = argc;
730}
731
732__dead__attribute__((__noreturn__)) void
733usage(void)
734{
735 (void)fprintf(stderr(&__sF[2]),
736 "usage: mount [-AadfNruvw] [-t type]\n"
737 " mount [-dfrsuvw] special | node\n"
738 " mount [-dfruvw] [-o options] [-t type] special node\n");
739 exit(1);
740}
741
742int
743disklabelcheck(struct fstab *fs)
744{
745 char *labelfs;
746
747 if (strcmp(fs->fs_vfstype, "nfs") != 0 ||
748 strpbrk(fs->fs_spec, ":@") == NULL((void *)0)) {
749 labelfs = readlabelfs(fs->fs_spec, 0);
750 if (labelfs == NULL((void *)0) ||
751 strcmp(labelfs, fs->fs_vfstype) == 0)
752 return (0);
753 if (strcmp(fs->fs_vfstype, "ufs") == 0 &&
754 strcmp(labelfs, "ffs") == 0) {
755 warnx("%s: fstab uses outdated type 'ufs' -- fix please",
756 fs->fs_spec);
757 return (0);
758 }
759 if (strcmp(fs->fs_vfstype, "mfs") == 0 &&
760 strcmp(labelfs, "ffs") == 0)
761 return (0);
762 warnx("%s: fstab type %s != disklabel type %s",
763 fs->fs_spec, fs->fs_vfstype, labelfs);
764 return (1);
765 }
766 return (0);
767}