1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29 /*
30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 * The Regents of the University of California
32 * All Rights Reserved
33 *
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
36 * contributors.
37 */
38
39 /*
40 * mount
41 */
42 #include <ctype.h>
43 #include <string.h>
44 #include <fcntl.h>
45 #include <signal.h>
46 #include <poll.h>
47 #include <sys/mkdev.h>
48 #include <sys/param.h>
49 #include <sys/types.h>
50 #include <sys/mntent.h>
51 #include <stdlib.h>
52
53 #define bcopy(f, t, n) memcpy(t, f, n)
54 #define bzero(s, n) memset(s, 0, n)
55 #define bcmp(s, d, n) memcmp(s, d, n)
56
57 #define index(s, r) strchr(s, r)
58 #define rindex(s, r) strrchr(s, r)
59
60 #include <errno.h>
61 #include <sys/vfs.h>
62 #include <sys/stat.h>
63 #include <stdio.h>
64 #include <unistd.h>
65 #include <sys/mnttab.h>
66 #include <sys/mount.h>
67 #include <sys/mntio.h>
68 #include <sys/wait.h>
69 #include <sys/fstyp.h>
70 #include <sys/fsid.h>
71 #include <sys/vfstab.h>
72 #include <sys/filio.h>
73 #include <sys/fs/ufs_fs.h>
74
75 #include <sys/fs/ufs_mount.h>
76 #include <sys/fs/ufs_filio.h>
77
78 #include <locale.h>
79 #include <fslib.h>
80
81 static int ro = 0;
82 static int largefiles = 0; /* flag - add default nolargefiles to mnttab */
83
84 static int gflg = 0;
85 static int mflg = 0;
86 static int Oflg = 0;
87 static int qflg = 0;
88
89 #define NAME_MAX 64 /* sizeof "fstype myname" */
90
91 static int checkislog(char *);
92 static void disable_logging(char *, char *);
93 static int eatmntopt(struct mnttab *, char *);
94 static void enable_logging(char *, char *);
95 static void fixopts(struct mnttab *, char *);
96 static void mountfs(struct mnttab *);
97 static void replace_opts(char *, int, char *, char *);
98 static int replace_opts_dflt(char *, int, const char *, const char *);
99 static void rmopt(struct mnttab *, char *);
100 static void rpterr(char *, char *);
101 static void usage(void);
102
103 static char fstype[] = MNTTYPE_UFS;
104 static char opts[MAX_MNTOPT_STR];
105 static char typename[NAME_MAX], *myname;
106 static char *fop_subopts[] = { MNTOPT_ONERROR, NULL };
107 #define NOMATCH (-1)
108 #define ONERROR (0) /* index within fop_subopts */
109
110 static struct fop_subopt {
111 char *str;
112 int flag;
113 } fop_subopt_list[] = {
114 { UFSMNT_ONERROR_PANIC_STR, UFSMNT_ONERROR_PANIC },
115 { UFSMNT_ONERROR_LOCK_STR, UFSMNT_ONERROR_LOCK },
116 { UFSMNT_ONERROR_UMOUNT_STR, UFSMNT_ONERROR_UMOUNT },
117 { NULL, UFSMNT_ONERROR_DEFAULT }
118 };
119
120
121 /*
122 * Check if the specified filesystem is already mounted.
123 */
124 static boolean_t
in_mnttab(char * mountp)125 in_mnttab(char *mountp)
126 {
127 FILE *file;
128 int found = B_FALSE;
129 struct mnttab mntent;
130
131 if ((file = fopen(MNTTAB, "r")) == NULL)
132 return (B_FALSE);
133 while (getmntent(file, &mntent) == 0) {
134 if (mntent.mnt_mountp != NULL &&
135 strcmp(mntent.mnt_mountp, mountp) == 0 &&
136 mntent.mnt_fstype != NULL &&
137 strcmp(mntent.mnt_fstype, MNTTYPE_UFS) == 0) {
138 found = B_TRUE;
139 break;
140 }
141 }
142 (void) fclose(file);
143 return (found);
144 }
145
146 /*
147 * Find opt in mntopt
148 */
149 static char *
findopt(char * mntopt,char * opt)150 findopt(char *mntopt, char *opt)
151 {
152 int nc, optlen = strlen(opt);
153
154 while (*mntopt) {
155 nc = strcspn(mntopt, ", =");
156 if (strncmp(mntopt, opt, nc) == 0)
157 if (optlen == nc)
158 return (mntopt);
159 mntopt += nc;
160 mntopt += strspn(mntopt, ", =");
161 }
162 return (NULL);
163 }
164
165 int
main(int argc,char * argv[])166 main(int argc, char *argv[])
167 {
168 struct mnttab mnt;
169 int c;
170
171 (void) setlocale(LC_ALL, "");
172 #if !defined(TEXT_DOMAIN)
173 #define TEXT_DOMAIN "SYS_TEST"
174 #endif
175 (void) textdomain(TEXT_DOMAIN);
176
177 myname = strrchr(argv[0], '/');
178 if (myname)
179 myname++;
180 else
181 myname = argv[0];
182 (void) snprintf(typename, sizeof (typename), "%s %s", fstype, myname);
183 argv[0] = typename;
184
185 opts[0] = '\0';
186
187 /*
188 * Set options
189 */
190 while ((c = getopt(argc, argv, "gmo:pqrVO")) != EOF) {
191 switch (c) {
192
193 case 'g':
194 gflg++;
195 break;
196
197 case 'o':
198 if (strlcpy(opts, optarg, sizeof (opts)) >=
199 sizeof (opts)) {
200 (void) fprintf(stderr, gettext("option string "
201 "argument too long\n"));
202 }
203 break;
204
205 case 'O':
206 Oflg++;
207 break;
208
209 case 'r':
210 ro++;
211 break;
212
213 case 'm':
214 mflg++;
215 break;
216
217 case 'q':
218 qflg++;
219 break;
220
221 default:
222 usage();
223 }
224 }
225
226 if ((argc - optind) != 2)
227 usage();
228
229 mnt.mnt_special = argv[optind];
230 mnt.mnt_mountp = argv[optind+1];
231 mnt.mnt_fstype = fstype;
232
233 /*
234 * Process options. The resulting options string overwrites the
235 * original.
236 *
237 * XXX: This code doesn't do a good job of resolving options that are
238 * specified multiple times or that are given in conflicting
239 * forms (e.g., both "largefiles" and "nolargefiles"). It also
240 * doesn't produce well defined behavior for options that may
241 * also be specified as flags (e.g, "-r" and "ro"/"rw") when both
242 * are present.
243 *
244 * The proper way to deal with such conflicts is to start with
245 * the default value (i.e., the one if no flag or option is
246 * specified), override it with the last mentioned option pair
247 * in the -o option string, and finally, override that with
248 * the flag value. This allows "mount -r" command to mount a
249 * file system read only that is listed rw in /etc/vfstab.
250 */
251 mnt.mnt_mntopts = opts;
252 if (findopt(mnt.mnt_mntopts, "m"))
253 mflg++;
254 if ((gflg || findopt(mnt.mnt_mntopts, MNTOPT_GLOBAL)) &&
255 findopt(mnt.mnt_mntopts, MNTOPT_NBMAND)) {
256 (void) fprintf(stderr, gettext("NBMAND option not supported on"
257 " global filesystem\n"));
258 exit(32);
259 }
260
261 replace_opts(opts, ro, MNTOPT_RO, MNTOPT_RW);
262 replace_opts(opts, largefiles, MNTOPT_NOLARGEFILES, MNTOPT_LARGEFILES);
263 gflg = replace_opts_dflt(opts, gflg, MNTOPT_GLOBAL, MNTOPT_NOGLOBAL);
264
265 if (findopt(mnt.mnt_mntopts, MNTOPT_RQ)) {
266 rmopt(&mnt, MNTOPT_RQ);
267 replace_opts(opts, 1, MNTOPT_QUOTA, MNTOPT_NOQUOTA);
268 }
269
270 mountfs(&mnt);
271 return (0);
272 }
273
274 static void
reportlogerror(int ret,char * mp,char * special,char * cmd,fiolog_t * flp)275 reportlogerror(int ret, char *mp, char *special, char *cmd, fiolog_t *flp)
276 {
277 /* No error */
278 if ((ret != -1) && (flp->error == FIOLOG_ENONE))
279 return;
280
281 /* logging was not enabled/disabled */
282 if (ret == -1 || flp->error != FIOLOG_ENONE)
283 (void) fprintf(stderr, gettext("Could not %s logging"
284 " for %s on %s.\n"), cmd, mp, special);
285
286 /* ioctl returned error */
287 if (ret == -1)
288 return;
289
290 /* Some more info */
291 switch (flp->error) {
292 case FIOLOG_ENONE :
293 if (flp->nbytes_requested &&
294 (flp->nbytes_requested != flp->nbytes_actual)) {
295 (void) fprintf(stderr, gettext("The log has been"
296 " resized from %d bytes to %d bytes.\n"),
297 flp->nbytes_requested,
298 flp->nbytes_actual);
299 }
300 return;
301 case FIOLOG_ETRANS :
302 (void) fprintf(stderr, gettext("Solaris Volume Manager logging"
303 " is already enabled.\n"));
304 (void) fprintf(stderr, gettext("Please see the"
305 " commands metadetach(8)"
306 " or metaclear(8).\n"));
307 break;
308 case FIOLOG_EROFS :
309 (void) fprintf(stderr, gettext("File system is mounted read "
310 "only.\n"));
311 (void) fprintf(stderr, gettext("Please see the remount "
312 "option described in mount_ufs(8).\n"));
313 break;
314 case FIOLOG_EULOCK :
315 (void) fprintf(stderr, gettext("File system is locked.\n"));
316 (void) fprintf(stderr, gettext("Please see the -u option "
317 "described in lockfs(8).\n"));
318 break;
319 case FIOLOG_EWLOCK :
320 (void) fprintf(stderr, gettext("The file system could not be"
321 " write locked.\n"));
322 (void) fprintf(stderr, gettext("Please see the -w option "
323 "described in lockfs(8).\n"));
324 break;
325 case FIOLOG_ECLEAN :
326 (void) fprintf(stderr, gettext("The file system may not be"
327 " stable.\n"));
328 (void) fprintf(stderr, gettext("Please see the -n option"
329 " for fsck(8).\n"));
330 break;
331 case FIOLOG_ENOULOCK :
332 (void) fprintf(stderr, gettext("The file system could not be"
333 " unlocked.\n"));
334 (void) fprintf(stderr, gettext("Please see the -u option "
335 "described in lockfs(8).\n"));
336 break;
337 default :
338 (void) fprintf(stderr, gettext("Unknown internal error"
339 " %d.\n"), flp->error);
340 break;
341 }
342 }
343
344 static int
checkislog(char * mp)345 checkislog(char *mp)
346 {
347 int fd;
348 uint32_t islog;
349
350 fd = open(mp, O_RDONLY);
351 islog = 0;
352 (void) ioctl(fd, _FIOISLOG, &islog);
353 (void) close(fd);
354 return ((int)islog);
355 }
356
357 static void
enable_logging(char * mp,char * special)358 enable_logging(char *mp, char *special)
359 {
360 int fd, ret, islog;
361 fiolog_t fl;
362
363 fd = open(mp, O_RDONLY);
364 if (fd == -1) {
365 perror(mp);
366 return;
367 }
368 fl.nbytes_requested = 0;
369 fl.nbytes_actual = 0;
370 fl.error = FIOLOG_ENONE;
371 ret = ioctl(fd, _FIOLOGENABLE, &fl);
372 if (ret == -1)
373 perror(mp);
374 (void) close(fd);
375
376 /* is logging enabled? */
377 islog = checkislog(mp);
378
379 /* report errors, if any */
380 if (ret == -1 || !islog)
381 reportlogerror(ret, mp, special, "enable", &fl);
382 }
383
384 static void
disable_logging(char * mp,char * special)385 disable_logging(char *mp, char *special)
386 {
387 int fd, ret, islog;
388 fiolog_t fl;
389
390 fd = open(mp, O_RDONLY);
391 if (fd == -1) {
392 perror(mp);
393 return;
394 }
395 fl.error = FIOLOG_ENONE;
396 ret = ioctl(fd, _FIOLOGDISABLE, &fl);
397 if (ret == -1)
398 perror(mp);
399 (void) close(fd);
400
401 /* is logging enabled? */
402 islog = checkislog(mp);
403
404 /* report errors, if any */
405 if (ret == -1 || islog)
406 reportlogerror(ret, mp, special, "disable", &fl);
407 }
408
409
410 /*
411 * attempt to mount file system, return errno or 0
412 */
413 void
mountfs(struct mnttab * mnt)414 mountfs(struct mnttab *mnt)
415 {
416 char opt[MAX_MNTOPT_STR];
417 char opt2[MAX_MNTOPT_STR];
418 char *opts = opt;
419 int flags = MS_OPTIONSTR;
420 struct ufs_args args;
421 int need_separator = 0;
422 int mount_attempts = 5;
423
424 (void) bzero((char *)&args, sizeof (args));
425 (void) strcpy(opts, mnt->mnt_mntopts);
426 opt2[0] = '\0';
427
428 flags |= Oflg ? MS_OVERLAY : 0;
429 flags |= eatmntopt(mnt, MNTOPT_RO) ? MS_RDONLY : 0;
430 flags |= eatmntopt(mnt, MNTOPT_REMOUNT) ? MS_REMOUNT : 0;
431 flags |= eatmntopt(mnt, MNTOPT_GLOBAL) ? MS_GLOBAL : 0;
432
433 if (eatmntopt(mnt, MNTOPT_NOINTR))
434 args.flags |= UFSMNT_NOINTR;
435 if (eatmntopt(mnt, MNTOPT_INTR))
436 args.flags &= ~UFSMNT_NOINTR;
437 if (eatmntopt(mnt, MNTOPT_SYNCDIR))
438 args.flags |= UFSMNT_SYNCDIR;
439 if (eatmntopt(mnt, MNTOPT_FORCEDIRECTIO)) {
440 args.flags |= UFSMNT_FORCEDIRECTIO;
441 args.flags &= ~UFSMNT_NOFORCEDIRECTIO;
442 }
443 if (eatmntopt(mnt, MNTOPT_NOFORCEDIRECTIO)) {
444 args.flags |= UFSMNT_NOFORCEDIRECTIO;
445 args.flags &= ~UFSMNT_FORCEDIRECTIO;
446 }
447 if (eatmntopt(mnt, MNTOPT_NOSETSEC))
448 args.flags |= UFSMNT_NOSETSEC;
449 if (eatmntopt(mnt, MNTOPT_LARGEFILES))
450 args.flags |= UFSMNT_LARGEFILES;
451 if (eatmntopt(mnt, MNTOPT_NOLARGEFILES))
452 args.flags &= ~UFSMNT_LARGEFILES;
453 args.flags |= UFSMNT_LOGGING; /* default is logging */
454 (void) eatmntopt(mnt, MNTOPT_LOGGING);
455 if (eatmntopt(mnt, MNTOPT_NOLOGGING))
456 args.flags &= ~UFSMNT_LOGGING;
457 if (eatmntopt(mnt, MNTOPT_NOATIME))
458 args.flags |= UFSMNT_NOATIME;
459 if (eatmntopt(mnt, MNTOPT_DFRATIME))
460 args.flags &= ~UFSMNT_NODFRATIME;
461 if (eatmntopt(mnt, MNTOPT_NODFRATIME))
462 args.flags |= UFSMNT_NODFRATIME;
463
464 while (*opts != '\0') {
465 char *argval;
466
467 switch (getsubopt(&opts, fop_subopts, &argval)) {
468 case ONERROR:
469 if (argval) {
470 struct fop_subopt *s;
471 int found = 0;
472
473 for (s = fop_subopt_list;
474 s->str && !found;
475 s++) {
476 if (strcmp(argval, s->str) == 0) {
477 args.flags |= s->flag;
478 found = 1;
479 }
480 }
481 if (!found) {
482 usage();
483 }
484
485 if (need_separator)
486 (void) strcat(opt2, ",");
487 (void) strcat(opt2, MNTOPT_ONERROR);
488 (void) strcat(opt2, "=");
489 (void) strcat(opt2, argval);
490 need_separator = 1;
491
492 } else {
493 args.flags |= UFSMNT_ONERROR_DEFAULT;
494 }
495 break;
496
497 case NOMATCH:
498 default:
499 if (argval) {
500 if (need_separator)
501 (void) strcat(opt2, ",");
502 (void) strcat(opt2, argval);
503 need_separator = 1;
504 }
505 break;
506
507 }
508 }
509
510 if (*opt2 != '\0')
511 (void) strcpy(opt, opt2);
512 opts = opt;
513 if ((args.flags & UFSMNT_ONERROR_FLGMASK) == 0)
514 args.flags |= UFSMNT_ONERROR_DEFAULT;
515
516 (void) signal(SIGHUP, SIG_IGN);
517 (void) signal(SIGQUIT, SIG_IGN);
518 (void) signal(SIGINT, SIG_IGN);
519
520 errno = 0;
521 flags |= MS_DATA | MS_OPTIONSTR;
522 if (mflg)
523 flags |= MS_NOMNTTAB;
524 if (flags & MS_REMOUNT) {
525 replace_opts(mnt->mnt_mntopts, 1, MNTOPT_RW, MNTOPT_RO);
526 }
527 fixopts(mnt, opts);
528
529 /*
530 * For global filesystems we want to pass in logging option
531 * so that it shows up in the mnttab of all nodes. We add
532 * logging option if its not specified.
533 */
534 if (gflg || findopt(mnt->mnt_mntopts, MNTOPT_GLOBAL)) {
535 if (!(flags & MS_RDONLY)) {
536 if (mnt->mnt_mntopts[0] != '\0')
537 (void) strcat(mnt->mnt_mntopts, ",");
538 (void) strcat(mnt->mnt_mntopts, MNTOPT_LOGGING);
539 args.flags |= UFSMNT_LOGGING;
540 } else {
541 /*
542 * Turn off logging for read only global mounts.
543 * It was set to logging as default above.
544 */
545 if (mnt->mnt_mntopts[0] != '\0')
546 (void) strcat(mnt->mnt_mntopts, ",");
547 (void) strcat(mnt->mnt_mntopts, MNTOPT_NOLOGGING);
548 args.flags &= ~UFSMNT_LOGGING;
549 }
550 }
551
552 again: if (mount(mnt->mnt_special, mnt->mnt_mountp, flags, fstype,
553 &args, sizeof (args), mnt->mnt_mntopts, MAX_MNTOPT_STR) != 0) {
554 if (errno == EBUSY && !(flags & MS_OVERLAY)) {
555 /*
556 * Because of bug 6176743, any attempt to mount any
557 * filesystem could fail for reasons described in that
558 * bug. We're trying to detect that situation here by
559 * checking that the filesystem we're mounting is not
560 * in /etc/mnttab yet. When that bug is fixed, this
561 * code can be removed.
562 */
563 if (!in_mnttab(mnt->mnt_mountp) &&
564 mount_attempts-- > 0) {
565 (void) poll(NULL, 0, 50);
566 goto again;
567 }
568 }
569 rpterr(mnt->mnt_special, mnt->mnt_mountp);
570 exit(32);
571 }
572
573 if (!(flags & MS_RDONLY)) {
574 if (args.flags & UFSMNT_LOGGING)
575 enable_logging(mnt->mnt_mountp, mnt->mnt_special);
576 else
577 disable_logging(mnt->mnt_mountp, mnt->mnt_special);
578 }
579
580 if (!qflg) {
581 cmp_requested_to_actual_options(opts, mnt->mnt_mntopts,
582 mnt->mnt_special, mnt->mnt_mountp);
583 }
584
585 if (checkislog(mnt->mnt_mountp)) {
586 /* update mnttab file if necessary */
587 if (!mflg) {
588 struct stat64 statb;
589 struct mnttagdesc mtdesc;
590 int fd;
591
592 if (stat64(mnt->mnt_mountp, &statb) != 0)
593 exit(32);
594 /* do tag ioctl */
595 mtdesc.mtd_major = major(statb.st_dev);
596 mtdesc.mtd_minor = minor(statb.st_dev);
597 mtdesc.mtd_mntpt = mnt->mnt_mountp;
598 mtdesc.mtd_tag = MNTOPT_LOGGING;
599 if ((fd = open(MNTTAB, O_RDONLY, 0)) < 0)
600 exit(32);
601 if (ioctl(fd, MNTIOC_SETTAG, &mtdesc) != 0) {
602 (void) close(fd);
603 exit(32);
604 }
605 (void) close(fd);
606 }
607 }
608 exit(0);
609 }
610
611 /*
612 * same as findopt but remove the option from the option string and return
613 * true or false
614 */
615 static int
eatmntopt(struct mnttab * mnt,char * opt)616 eatmntopt(struct mnttab *mnt, char *opt)
617 {
618 int has;
619
620 has = (findopt(mnt->mnt_mntopts, opt) != NULL);
621 rmopt(mnt, opt);
622 return (has);
623 }
624
625 /*
626 * remove an option string from the option list
627 */
628 static void
rmopt(struct mnttab * mnt,char * opt)629 rmopt(struct mnttab *mnt, char *opt)
630 {
631 char *str;
632 char *optstart;
633
634 while (optstart = findopt(mnt->mnt_mntopts, opt)) {
635 for (str = optstart;
636 *str != ',' && *str != '\0' && *str != ' ';
637 str++)
638 /* NULL */;
639 if (*str == ',') {
640 str++;
641 } else if (optstart != mnt->mnt_mntopts) {
642 optstart--;
643 }
644 while (*optstart++ = *str++)
645 ;
646 }
647 }
648
649 /*
650 * mnt->mnt_ops has un-eaten opts, opts is the original opts list.
651 * Set mnt->mnt_opts to the original, the kernel will then remove
652 * the ones it cannot deal with.
653 * Set "opts" to the the original options for later comparison in
654 * cmp_....(). But strip the options which aren't returned by
655 * the kernel: "noglobal", "global" and "quota".
656 * And strip the options which aren't set through mount: "logging",
657 * "nologging" from those passed to mount(2).
658 */
659 static void
fixopts(struct mnttab * mnt,char * opts)660 fixopts(struct mnttab *mnt, char *opts)
661 {
662 struct mnttab omnt;
663
664 omnt.mnt_mntopts = opts;
665
666 /*
667 * Options not passed to the kernel and possibly not returned;
668 * these are dealt with using ioctl; and the ioctl may fail.
669 */
670 rmopt(&omnt, MNTOPT_LOGGING);
671 rmopt(&omnt, MNTOPT_NOLOGGING);
672
673 /*
674 * Set the options for ``/etc/mnttab'' to be the original
675 * options from main(); except for the option "f" and "remount".
676 */
677 (void) strlcpy(mnt->mnt_mntopts, opts, MAX_MNTOPT_STR);
678 rmopt(mnt, "f");
679 rmopt(mnt, MNTOPT_REMOUNT);
680
681 rmopt(&omnt, MNTOPT_GLOBAL);
682 rmopt(&omnt, MNTOPT_NOGLOBAL);
683 rmopt(&omnt, MNTOPT_QUOTA);
684 }
685
686 static void
usage(void)687 usage(void)
688 {
689 (void) fprintf(stdout, gettext(
690 "ufs usage:\n"
691 "mount [-F ufs] [generic options] [-o suboptions] {special | mount_point}\n"));
692 (void) fprintf(stdout, gettext(
693 "\tsuboptions are: \n"
694 "\t ro,rw,nosuid,remount,f,m,\n"
695 "\t global,noglobal,\n"
696 "\t largefiles,nolargefiles,\n"
697 "\t forcedirectio,noforcedirectio\n"
698 "\t logging,nologging,\n"
699 "\t nbmand,nonbmand,\n"
700 "\t onerror[={panic | lock | umount}]\n"));
701
702 exit(32);
703 }
704
705 /*
706 * Returns the next option in the option string.
707 */
708 static char *
getnextopt(char ** p)709 getnextopt(char **p)
710 {
711 char *cp = *p;
712 char *retstr;
713
714 while (*cp && isspace(*cp))
715 cp++;
716 retstr = cp;
717 while (*cp && *cp != ',')
718 cp++;
719 /* strip empty options */
720 while (*cp == ',') {
721 *cp = '\0';
722 cp++;
723 }
724 *p = cp;
725 return (retstr);
726 }
727
728 /*
729 * "trueopt" and "falseopt" are two settings of a Boolean option.
730 * If "flag" is true, forcibly set the option to the "true" setting; otherwise,
731 * if the option isn't present, set it to the false setting.
732 */
733 static void
replace_opts(char * options,int flag,char * trueopt,char * falseopt)734 replace_opts(char *options, int flag, char *trueopt, char *falseopt)
735 {
736 char *f;
737 char *tmpoptsp;
738 int found;
739 char tmptopts[MNTMAXSTR];
740
741 (void) strcpy(tmptopts, options);
742 tmpoptsp = tmptopts;
743 (void) strcpy(options, "");
744
745 found = 0;
746 for (f = getnextopt(&tmpoptsp); *f; f = getnextopt(&tmpoptsp)) {
747 if (options[0] != '\0')
748 (void) strcat(options, ",");
749 if (strcmp(f, trueopt) == 0) {
750 (void) strcat(options, f);
751 found++;
752 } else if (strcmp(f, falseopt) == 0) {
753 if (flag)
754 (void) strcat(options, trueopt);
755 else
756 (void) strcat(options, f);
757 found++;
758 } else
759 (void) strcat(options, f);
760 }
761 if (!found) {
762 if (options[0] != '\0')
763 (void) strcat(options, ",");
764 (void) strcat(options, flag ? trueopt : falseopt);
765 }
766 }
767
768 /*
769 * "trueopt" and "falseopt" are two settings of a Boolean option and "dflt" is
770 * a default value for the option. Rewrite the contents of options to include
771 * only the last mentioned occurrence of trueopt and falseopt. If neither is
772 * mentioned, append one or the other to options, according to the value of
773 * dflt. Return the resulting value of the option in boolean form.
774 *
775 * Note that the routine is implemented to have the resulting occurrence of
776 * trueopt or falseopt appear at the end of the resulting option string.
777 *
778 * N.B. This routine should take the place of replace_opts, but there are
779 * probably some compatibility issues to resolve before doing so. It
780 * should certainly be used to handle new options that don't have
781 * compatibility issues.
782 */
783 static int
replace_opts_dflt(char * options,int dflt,const char * trueopt,const char * falseopt)784 replace_opts_dflt(
785 char *options,
786 int dflt,
787 const char *trueopt,
788 const char *falseopt)
789 {
790 char *f;
791 char *tmpoptsp;
792 int last;
793 char tmptopts[MNTMAXSTR];
794
795 /*
796 * Transfer the contents of options to tmptopts, in anticipation of
797 * copying a subset of the contents back to options.
798 */
799 (void) strcpy(tmptopts, options);
800 tmpoptsp = tmptopts;
801 (void) strcpy(options, "");
802
803 /*
804 * Loop over each option value, copying non-matching values back into
805 * options and updating the last seen occurrence of trueopt or
806 * falseopt.
807 */
808 last = dflt;
809 for (f = getnextopt(&tmpoptsp); *f; f = getnextopt(&tmpoptsp)) {
810 /* Check for both forms of the option of interest. */
811 if (strcmp(f, trueopt) == 0) {
812 last = 1;
813 } else if (strcmp(f, falseopt) == 0) {
814 last = 0;
815 } else {
816 /* Not what we're looking for; transcribe. */
817 if (options[0] != '\0')
818 (void) strcat(options, ",");
819 (void) strcat(options, f);
820 }
821 }
822
823 /*
824 * Transcribe the correct form of the option of interest, using the
825 * default value if it wasn't overwritten above.
826 */
827 if (options[0] != '\0')
828 (void) strcat(options, ",");
829 (void) strcat(options, last ? trueopt : falseopt);
830
831 return (last);
832 }
833
834 static void
rpterr(char * bs,char * mp)835 rpterr(char *bs, char *mp)
836 {
837 switch (errno) {
838 case EPERM:
839 (void) fprintf(stderr, gettext("%s: Insufficient privileges\n"),
840 myname);
841 break;
842 case ENXIO:
843 (void) fprintf(stderr, gettext("%s: %s no such device\n"),
844 myname, bs);
845 break;
846 case ENOTDIR:
847 (void) fprintf(stderr,
848 gettext(
849 "%s: %s not a directory\n\tor a component of %s is not a directory\n"),
850 myname, mp, bs);
851 break;
852 case ENOENT:
853 (void) fprintf(stderr, gettext(
854 "%s: %s or %s, no such file or directory\n"),
855 myname, bs, mp);
856 break;
857 case EINVAL:
858 (void) fprintf(stderr, gettext("%s: %s is not this fstype\n"),
859 myname, bs);
860 break;
861 case EBUSY:
862 (void) fprintf(stderr,
863 gettext("%s: %s is already mounted or %s is busy\n"),
864 myname, bs, mp);
865 break;
866 case ENOTBLK:
867 (void) fprintf(stderr, gettext(
868 "%s: %s not a block device\n"), myname, bs);
869 break;
870 case EROFS:
871 (void) fprintf(stderr, gettext("%s: %s write-protected\n"),
872 myname, bs);
873 break;
874 case ENOSPC:
875 (void) fprintf(stderr, gettext(
876 "%s: The state of %s is not okay\n"
877 "\tand it was attempted to be mounted read/write\n"),
878 myname, bs);
879 (void) printf(gettext(
880 "mount: Please run fsck and try again\n"));
881 break;
882 case EFBIG:
883 (void) fprintf(stderr, gettext(
884 "%s: Large files may be present on %s,\n"
885 "\tand it was attempted to be mounted nolargefiles\n"),
886 myname, bs);
887 break;
888 default:
889 perror(myname);
890 (void) fprintf(stderr, gettext("%s: Cannot mount %s\n"),
891 myname, bs);
892 }
893 }
894