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 2006 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 (!flags & MS_RDONLY) { 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 } else { 543 /* 544 * Turn off logging for read only global mounts. 545 * It was set to logging as default above. 546 */ 547 if (mnt->mnt_mntopts != '\0') 548 (void) strcat(mnt->mnt_mntopts, ","); 549 (void) strcat(mnt->mnt_mntopts, MNTOPT_NOLOGGING); 550 args.flags &= ~UFSMNT_LOGGING; 551 } 552 } 553 554 again: if (mount(mnt->mnt_special, mnt->mnt_mountp, flags, fstype, 555 &args, sizeof (args), mnt->mnt_mntopts, MAX_MNTOPT_STR) != 0) { 556 if (errno == EBUSY && !(flags & MS_OVERLAY)) { 557 /* 558 * Because of bug 6176743, any attempt to mount any 559 * filesystem could fail for reasons described in that 560 * bug. We're trying to detect that situation here by 561 * checking that the filesystem we're mounting is not 562 * in /etc/mnttab yet. When that bug is fixed, this 563 * code can be removed. 564 */ 565 if (!in_mnttab(mnt->mnt_mountp) && 566 mount_attempts-- > 0) { 567 (void) poll(NULL, 0, 50); 568 goto again; 569 } 570 } 571 rpterr(mnt->mnt_special, mnt->mnt_mountp); 572 exit(32); 573 } 574 575 if (!(flags & MS_RDONLY)) { 576 if (args.flags & UFSMNT_LOGGING) 577 enable_logging(mnt->mnt_mountp, mnt->mnt_special); 578 else 579 disable_logging(mnt->mnt_mountp, mnt->mnt_special); 580 } 581 582 if (!qflg) { 583 cmp_requested_to_actual_options(opts, mnt->mnt_mntopts, 584 mnt->mnt_special, mnt->mnt_mountp); 585 } 586 587 if (checkislog(mnt->mnt_mountp)) { 588 /* update mnttab file if necessary */ 589 if (!mflg) { 590 struct stat64 statb; 591 struct mnttagdesc mtdesc; 592 int fd; 593 594 if (stat64(mnt->mnt_mountp, &statb) != 0) 595 exit(32); 596 /* do tag ioctl */ 597 mtdesc.mtd_major = major(statb.st_dev); 598 mtdesc.mtd_minor = minor(statb.st_dev); 599 mtdesc.mtd_mntpt = mnt->mnt_mountp; 600 mtdesc.mtd_tag = MNTOPT_LOGGING; 601 if ((fd = open(MNTTAB, O_RDONLY, 0)) < 0) 602 exit(32); 603 if (ioctl(fd, MNTIOC_SETTAG, &mtdesc) != 0) { 604 (void) close(fd); 605 exit(32); 606 } 607 (void) close(fd); 608 } 609 } 610 exit(0); 611 } 612 613 /* 614 * same as findopt but remove the option from the option string and return 615 * true or false 616 */ 617 static int 618 eatmntopt(struct mnttab *mnt, char *opt) 619 { 620 int has; 621 622 has = (findopt(mnt->mnt_mntopts, opt) != NULL); 623 rmopt(mnt, opt); 624 return (has); 625 } 626 627 /* 628 * remove an option string from the option list 629 */ 630 static void 631 rmopt(struct mnttab *mnt, char *opt) 632 { 633 char *str; 634 char *optstart; 635 636 while (optstart = findopt(mnt->mnt_mntopts, opt)) { 637 for (str = optstart; 638 *str != ',' && *str != '\0' && *str != ' '; 639 str++) 640 /* NULL */; 641 if (*str == ',') { 642 str++; 643 } else if (optstart != mnt->mnt_mntopts) { 644 optstart--; 645 } 646 while (*optstart++ = *str++) 647 ; 648 } 649 } 650 651 /* 652 * mnt->mnt_ops has un-eaten opts, opts is the original opts list. 653 * Set mnt->mnt_opts to the original, the kernel will then remove 654 * the ones it cannot deal with. 655 * Set "opts" to the the original options for later comparison in 656 * cmp_....(). But strip the options which aren't returned by 657 * the kernel: "noglobal", "global" and "quota". 658 * And strip the options which aren't set through mount: "logging", 659 * "nologging" from those passed to mount(2). 660 */ 661 static void 662 fixopts(struct mnttab *mnt, char *opts) 663 { 664 struct mnttab omnt; 665 666 omnt.mnt_mntopts = opts; 667 668 /* 669 * Options not passed to the kernel and possibly not returned; 670 * these are dealt with using ioctl; and the ioctl may fail. 671 */ 672 rmopt(&omnt, MNTOPT_LOGGING); 673 rmopt(&omnt, MNTOPT_NOLOGGING); 674 675 /* 676 * Set the options for ``/etc/mnttab'' to be the original 677 * options from main(); except for the option "f" and "remount". 678 */ 679 (void) strlcpy(mnt->mnt_mntopts, opts, MAX_MNTOPT_STR); 680 rmopt(mnt, "f"); 681 rmopt(mnt, MNTOPT_REMOUNT); 682 683 rmopt(&omnt, MNTOPT_GLOBAL); 684 rmopt(&omnt, MNTOPT_NOGLOBAL); 685 rmopt(&omnt, MNTOPT_QUOTA); 686 } 687 688 static void 689 usage(void) 690 { 691 (void) fprintf(stdout, gettext( 692 "ufs usage:\n" 693 "mount [-F ufs] [generic options] [-o suboptions] {special | mount_point}\n")); 694 (void) fprintf(stdout, gettext( 695 "\tsuboptions are: \n" 696 "\t ro,rw,nosuid,remount,f,m,\n" 697 "\t global,noglobal,\n" 698 "\t largefiles,nolargefiles,\n" 699 "\t forcedirectio,noforcedirectio\n" 700 "\t logging,nologging,\n" 701 "\t nbmand,nonbmand,\n" 702 "\t onerror[={panic | lock | umount}]\n")); 703 704 exit(32); 705 } 706 707 /* 708 * Returns the next option in the option string. 709 */ 710 static char * 711 getnextopt(char **p) 712 { 713 char *cp = *p; 714 char *retstr; 715 716 while (*cp && isspace(*cp)) 717 cp++; 718 retstr = cp; 719 while (*cp && *cp != ',') 720 cp++; 721 /* strip empty options */ 722 while (*cp == ',') { 723 *cp = '\0'; 724 cp++; 725 } 726 *p = cp; 727 return (retstr); 728 } 729 730 /* 731 * "trueopt" and "falseopt" are two settings of a Boolean option. 732 * If "flag" is true, forcibly set the option to the "true" setting; otherwise, 733 * if the option isn't present, set it to the false setting. 734 */ 735 static void 736 replace_opts(char *options, int flag, char *trueopt, char *falseopt) 737 { 738 char *f; 739 char *tmpoptsp; 740 int found; 741 char tmptopts[MNTMAXSTR]; 742 743 (void) strcpy(tmptopts, options); 744 tmpoptsp = tmptopts; 745 (void) strcpy(options, ""); 746 747 found = 0; 748 for (f = getnextopt(&tmpoptsp); *f; f = getnextopt(&tmpoptsp)) { 749 if (options[0] != '\0') 750 (void) strcat(options, ","); 751 if (strcmp(f, trueopt) == 0) { 752 (void) strcat(options, f); 753 found++; 754 } else if (strcmp(f, falseopt) == 0) { 755 if (flag) 756 (void) strcat(options, trueopt); 757 else 758 (void) strcat(options, f); 759 found++; 760 } else 761 (void) strcat(options, f); 762 } 763 if (!found) { 764 if (options[0] != '\0') 765 (void) strcat(options, ","); 766 (void) strcat(options, flag ? trueopt : falseopt); 767 } 768 } 769 770 /* 771 * "trueopt" and "falseopt" are two settings of a Boolean option and "dflt" is 772 * a default value for the option. Rewrite the contents of options to include 773 * only the last mentioned occurrence of trueopt and falseopt. If neither is 774 * mentioned, append one or the other to options, according to the value of 775 * dflt. Return the resulting value of the option in boolean form. 776 * 777 * Note that the routine is implemented to have the resulting occurrence of 778 * trueopt or falseopt appear at the end of the resulting option string. 779 * 780 * N.B. This routine should take the place of replace_opts, but there are 781 * probably some compatibility issues to resolve before doing so. It 782 * should certainly be used to handle new options that don't have 783 * compatibility issues. 784 */ 785 static int 786 replace_opts_dflt( 787 char *options, 788 int dflt, 789 const char *trueopt, 790 const char *falseopt) 791 { 792 char *f; 793 char *tmpoptsp; 794 int last; 795 char tmptopts[MNTMAXSTR]; 796 797 /* 798 * Transfer the contents of options to tmptopts, in anticipation of 799 * copying a subset of the contents back to options. 800 */ 801 (void) strcpy(tmptopts, options); 802 tmpoptsp = tmptopts; 803 (void) strcpy(options, ""); 804 805 /* 806 * Loop over each option value, copying non-matching values back into 807 * options and updating the last seen occurrence of trueopt or 808 * falseopt. 809 */ 810 last = dflt; 811 for (f = getnextopt(&tmpoptsp); *f; f = getnextopt(&tmpoptsp)) { 812 /* Check for both forms of the option of interest. */ 813 if (strcmp(f, trueopt) == 0) { 814 last = 1; 815 } else if (strcmp(f, falseopt) == 0) { 816 last = 0; 817 } else { 818 /* Not what we're looking for; transcribe. */ 819 if (options[0] != '\0') 820 (void) strcat(options, ","); 821 (void) strcat(options, f); 822 } 823 } 824 825 /* 826 * Transcribe the correct form of the option of interest, using the 827 * default value if it wasn't overwritten above. 828 */ 829 if (options[0] != '\0') 830 (void) strcat(options, ","); 831 (void) strcat(options, last ? trueopt : falseopt); 832 833 return (last); 834 } 835 836 static void 837 rpterr(char *bs, char *mp) 838 { 839 switch (errno) { 840 case EPERM: 841 (void) fprintf(stderr, gettext("%s: Insufficient privileges\n"), 842 myname); 843 break; 844 case ENXIO: 845 (void) fprintf(stderr, gettext("%s: %s no such device\n"), 846 myname, bs); 847 break; 848 case ENOTDIR: 849 (void) fprintf(stderr, 850 gettext( 851 "%s: %s not a directory\n\tor a component of %s is not a directory\n"), 852 myname, mp, bs); 853 break; 854 case ENOENT: 855 (void) fprintf(stderr, gettext( 856 "%s: %s or %s, no such file or directory\n"), 857 myname, bs, mp); 858 break; 859 case EINVAL: 860 (void) fprintf(stderr, gettext("%s: %s is not this fstype\n"), 861 myname, bs); 862 break; 863 case EBUSY: 864 (void) fprintf(stderr, 865 gettext("%s: %s is already mounted or %s is busy\n"), 866 myname, bs, mp); 867 break; 868 case ENOTBLK: 869 (void) fprintf(stderr, gettext( 870 "%s: %s not a block device\n"), myname, bs); 871 break; 872 case EROFS: 873 (void) fprintf(stderr, gettext("%s: %s write-protected\n"), 874 myname, bs); 875 break; 876 case ENOSPC: 877 (void) fprintf(stderr, gettext( 878 "%s: The state of %s is not okay\n" 879 "\tand it was attempted to be mounted read/write\n"), 880 myname, bs); 881 (void) printf(gettext( 882 "mount: Please run fsck and try again\n")); 883 break; 884 case EFBIG: 885 (void) fprintf(stderr, gettext( 886 "%s: Large files may be present on %s,\n" 887 "\tand it was attempted to be mounted nolargefiles\n"), 888 myname, bs); 889 break; 890 default: 891 perror(myname); 892 (void) fprintf(stderr, gettext("%s: Cannot mount %s\n"), 893 myname, bs); 894 } 895 } 896