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 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 * 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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