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