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