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) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * Portions of this source code were derived from Berkeley 4.3 BSD 32 * under license from the Regents of the University of California. 33 */ 34 35 #pragma ident "%Z%%M% %I% %E% SMI" 36 37 /* 38 * 39 * mount.c 40 * 41 * Cachefs mount program. 42 */ 43 44 #include <locale.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <strings.h> 49 #include <stdarg.h> 50 #include <unistd.h> 51 #include <limits.h> 52 #include <errno.h> 53 #include <wait.h> 54 #include <ctype.h> 55 #include <fcntl.h> 56 #include <fslib.h> 57 #include <sys/types.h> 58 #include <sys/time.h> 59 #include <sys/param.h> 60 #include <sys/stat.h> 61 #include <sys/fcntl.h> 62 #include <sys/mount.h> 63 #include <sys/mntent.h> 64 #include <sys/mnttab.h> 65 #include <sys/mntio.h> 66 #include <sys/fs/cachefs_fs.h> 67 #include <sys/utsname.h> 68 #include <rpc/rpc.h> 69 #include <kstat.h> 70 #undef MAX 71 #include <nfs/nfs.h> 72 #include <nfs/nfs_clnt.h> 73 #include <sys/mkdev.h> 74 #include "../common/subr.h" 75 #include "../common/cachefsd.h" 76 77 char *cfs_opts[] = { 78 #define CFSOPT_BACKFSTYPE 0 79 "backfstype", 80 #define CFSOPT_CACHEDIR 1 81 "cachedir", 82 #define CFSOPT_CACHEID 2 83 "cacheid", 84 #define CFSOPT_BACKPATH 3 85 "backpath", 86 87 #define CFSOPT_WRITEAROUND 4 88 "write-around", 89 #define CFSOPT_NONSHARED 5 90 "non-shared", 91 92 #define CFSOPT_DISCONNECTABLE 6 93 "disconnectable", 94 #define CFSOPT_SOFT 7 95 "soft", 96 97 #define CFSOPT_NOCONST 8 98 "noconst", 99 #define CFSOPT_CODCONST 9 100 "demandconst", 101 102 #define CFSOPT_LOCALACCESS 10 103 "local-access", 104 #define CFSOPT_LAZYMOUNT 11 105 "lazy-mount", 106 107 #define CFSOPT_RW 12 108 "rw", 109 #define CFSOPT_RO 13 110 "ro", 111 #define CFSOPT_SUID 14 112 "suid", 113 #define CFSOPT_NOSUID 15 114 "nosuid", 115 #define CFSOPT_REMOUNT 16 116 "remount", 117 #define CFSOPT_FGSIZE 17 118 "fgsize", 119 #define CFSOPT_POPSIZE 18 120 "popsize", 121 #define CFSOPT_ACREGMIN 19 122 "acregmin", 123 #define CFSOPT_ACREGMAX 20 124 "acregmax", 125 #define CFSOPT_ACDIRMIN 21 126 "acdirmin", 127 #define CFSOPT_ACDIRMAX 22 128 "acdirmax", 129 #define CFSOPT_ACTIMEO 23 130 "actimeo", 131 #define CFSOPT_SLIDE 24 132 "slide", 133 #define CFSOPT_NOSETSEC 25 134 "nosec", /* XXX should we use MNTOPT_NOTSETSEC? */ 135 #define CFSOPT_LLOCK 26 136 "llock", 137 #define CFSOPT_NONOTIFY 27 138 "nonotify", 139 #define CFSOPT_SNR 28 140 "snr", 141 #define CFSOPT_NOFILL 29 142 "nofill", 143 #ifdef CFS_NFSV3_PASSTHROUGH 144 #define CFSOPT_NFSV3PASSTHROUGH 30 145 "nfsv3pass", 146 #endif /* CFS_NFSV3_PASSTHROUGH */ 147 NULL 148 }; 149 150 #define MNTTYPE_CFS "cachefs" /* XXX - to be added to mntent.h */ 151 /* XXX - and should be cachefs */ 152 #define CFS_DEF_DIR "/cache" /* XXX - should be added to cfs.h */ 153 154 #define bad(val) (val == NULL || !isdigit(*val)) 155 156 #define VFS_PATH "/usr/lib/fs" 157 #define ALT_PATH "/etc/fs" 158 159 /* forward references */ 160 void usage(char *msgp); 161 void pr_err(char *fmt, ...); 162 int set_cfs_args(char *optionp, struct cachefs_mountargs *margsp, int *mflagp, 163 char **backfstypepp, char **reducepp, int *notifyp, int *nfsv3pass); 164 int get_mount_point(char *cachedirp, char *specp, char **pathpp); 165 int dobackmnt(struct cachefs_mountargs *margsp, char *reducep, char *specp, 166 char *backfstypep, char *mynamep, int readonly); 167 void doexec(char *fstype, char **newargv, char *myname); 168 char *get_back_fsid(char *specp); 169 char *get_cacheid(char *, char *); 170 void record_mount(char *mntp, char *specp, char *backfsp, char *backfstypep, 171 char *cachedirp, char *cacheidp, char *optionp, char *reducep); 172 int daemon_notify(char *cachedirp, char *cacheidp); 173 int pingserver(char *backmntp); 174 int check_cache(char *cachedirp); 175 uint32_t cachefs_get_back_nfsvers(char *cfs_backfs, int nomnttab); 176 int cfs_nfsv4_build_opts(char *optionp, char *cfs_nfsv4ops); 177 178 int nomnttab; 179 int quiet; 180 /* 181 * 182 * main 183 * 184 * Description: 185 * Main routine for the cachefs mount program. 186 * Arguments: 187 * argc number of command line arguments 188 * argv list of command line arguments 189 * Returns: 190 * Returns 0 for success, 1 an error was encountered. 191 * Preconditions: 192 */ 193 194 main(int argc, char **argv) 195 { 196 char *myname; 197 char *optionp; 198 char *opigp; 199 int mflag; 200 int readonly; 201 struct cachefs_mountargs margs; 202 char *backfstypep; 203 char *reducep; 204 char *specp; 205 int xx; 206 int stat_loc; 207 char *newargv[20]; 208 char *mntp; 209 pid_t pid; 210 int mounted; 211 int c; 212 int lockid; 213 int Oflg; 214 char *strp; 215 char servname[33]; 216 int notify = 1; 217 struct stat64 statb; 218 struct mnttagdesc mtdesc; 219 char mops[MAX_MNTOPT_STR]; 220 char cfs_nfsv4ops[MAX_MNTOPT_STR]; 221 uint32_t nfsvers = 0; 222 uint32_t nfsvers_error = FALSE; 223 int nfsv3pass = 0; 224 (void) setlocale(LC_ALL, ""); 225 #if !defined(TEXT_DOMAIN) 226 #define TEXT_DOMAIN "SYS_TEST" 227 #endif 228 (void) textdomain(TEXT_DOMAIN); 229 230 if (argv[0]) { 231 myname = strrchr(argv[0], '/'); 232 if (myname) 233 myname++; 234 else 235 myname = argv[0]; 236 } else { 237 myname = "path unknown"; 238 } 239 240 optionp = NULL; 241 nomnttab = 0; 242 quiet = 0; 243 readonly = 0; 244 Oflg = 0; 245 cfs_nfsv4ops[0] = '\0'; 246 247 /* process command line options */ 248 while ((c = getopt(argc, argv, "mo:Orq")) != EOF) { 249 switch (c) { 250 case 'm': /* no entry in /etc/mnttab */ 251 nomnttab = 1; 252 break; 253 254 case 'o': 255 optionp = optarg; 256 break; 257 258 case 'O': 259 Oflg++; 260 break; 261 262 case 'r': /* read only mount */ 263 readonly = 1; 264 break; 265 266 case 'q': 267 quiet = 1; 268 break; 269 270 default: 271 usage("invalid option"); 272 return (1); 273 } 274 } 275 276 /* if -o not specified */ 277 if (optionp == NULL) { 278 usage(gettext("\"-o backfstype\" must be specified")); 279 return (1); 280 } 281 282 /* verify special device and mount point are specified */ 283 if (argc - optind < 2) { 284 usage(gettext("must specify special device and mount point")); 285 return (1); 286 } 287 288 /* Store mount point and special device. */ 289 specp = argv[argc - 2]; 290 mntp = argv[argc - 1]; 291 292 /* Initialize default mount values */ 293 margs.cfs_options.opt_flags = CFS_ACCESS_BACKFS; 294 margs.cfs_options.opt_popsize = DEF_POP_SIZE; 295 margs.cfs_options.opt_fgsize = DEF_FILEGRP_SIZE; 296 margs.cfs_fsid = NULL; 297 memset(margs.cfs_cacheid, 0, sizeof (margs.cfs_cacheid)); 298 margs.cfs_cachedir = CFS_DEF_DIR; 299 margs.cfs_backfs = NULL; 300 margs.cfs_acregmin = 0; 301 margs.cfs_acregmax = 0; 302 margs.cfs_acdirmin = 0; 303 margs.cfs_acdirmax = 0; 304 mflag = MS_OPTIONSTR; 305 if (nomnttab) 306 mflag |= MS_NOMNTTAB; 307 backfstypep = NULL; 308 309 /* process -o options */ 310 xx = set_cfs_args(optionp, &margs, &mflag, &backfstypep, &reducep, 311 ¬ify, &nfsv3pass); 312 if (xx) { 313 return (1); 314 } 315 strcpy(mops, optionp); 316 317 /* backfstype has to be specified */ 318 if (backfstypep == NULL) { 319 usage(gettext("\"-o backfstype\" must be specified")); 320 return (1); 321 } 322 323 if ((strcmp(backfstypep, "nfs") != 0) && 324 (strcmp(backfstypep, "hsfs") != 0)) { 325 pr_err(gettext("%s as backfstype is not supported."), 326 backfstypep); 327 return (1); 328 } 329 330 /* set default write mode if not specified */ 331 if ((margs.cfs_options.opt_flags & 332 (CFS_WRITE_AROUND|CFS_NONSHARED)) == 0) { 333 margs.cfs_options.opt_flags |= CFS_WRITE_AROUND; 334 if (strcmp(backfstypep, "hsfs") == 0) 335 mflag |= MS_RDONLY; 336 } 337 338 /* if read-only was specified with the -r option */ 339 if (readonly) { 340 mflag |= MS_RDONLY; 341 } 342 343 /* if overlay was specified with -O option */ 344 if (Oflg) { 345 mflag |= MS_OVERLAY; 346 } 347 348 /* get the fsid of the backfs and the cacheid */ 349 margs.cfs_fsid = get_back_fsid(specp); 350 if (margs.cfs_fsid == NULL) { 351 pr_err(gettext("out of memory")); 352 return (1); 353 } 354 355 /* 356 * If using this cachedir to mount a file system for the first time 357 * after reboot, the ncheck for the sanity of the cachedir 358 */ 359 if (first_time_ab(margs.cfs_cachedir)) 360 if (check_cache(margs.cfs_cachedir)) 361 return (1); 362 363 /* get the front file system cache id if necessary */ 364 if (margs.cfs_cacheid[0] == '\0') { 365 char *cacheid = get_cacheid(margs.cfs_fsid, mntp); 366 367 if (cacheid == NULL) { 368 pr_err(gettext("default cacheid too long")); 369 return (1); 370 } 371 372 strcpy(margs.cfs_cacheid, cacheid); 373 } 374 375 /* lock the cache directory shared */ 376 lockid = cachefs_dir_lock(margs.cfs_cachedir, 1); 377 if (lockid == -1) { 378 /* exit if could not get the lock */ 379 return (1); 380 } 381 382 /* if no mount point was specified and we are not remounting */ 383 mounted = 0; 384 if ((margs.cfs_backfs == NULL) && 385 (((mflag & MS_REMOUNT) == 0) || 386 (margs.cfs_options.opt_flags & CFS_SLIDE))) { 387 /* if a disconnectable mount */ 388 xx = 0; 389 if (margs.cfs_options.opt_flags & CFS_DISCONNECTABLE) { 390 /* see if the server is alive */ 391 xx = pingserver(specp); 392 } 393 394 /* attempt to mount the back file system */ 395 if (xx == 0) { 396 xx = dobackmnt(&margs, reducep, specp, backfstypep, 397 myname, readonly); 398 /* 399 * nfs mount exits with a value of 32 if a timeout 400 * error occurs trying the mount. 401 */ 402 if (xx && (xx != 32)) { 403 cachefs_dir_unlock(lockid); 404 rmdir(margs.cfs_backfs); 405 return (1); 406 } 407 if (xx == 0) 408 mounted = 1; 409 } 410 } 411 412 /* 413 * At this point the back file system should be mounted. 414 * Get NFS version information for the back filesystem if 415 * it is NFS. The version information is required 416 * because NFS version 4 is incompatible with cachefs 417 * and we provide pass-through support for NFS version 4 418 * with cachefs, aka the cachefs mount is installed but 419 * there is no caching. This is indicated to the kernel 420 * during the mount by setting the CFS_BACKFS_NFSV4 flag. 421 */ 422 if (margs.cfs_backfs != NULL && strcmp(backfstypep, "nfs") == 0) { 423 424 nfsvers = cachefs_get_back_nfsvers(margs.cfs_backfs, nomnttab); 425 switch (nfsvers) { 426 case 2: 427 break; 428 429 case 3: 430 if (nfsv3pass) { 431 /* Force pass through (for debugging) */ 432 margs.cfs_options.opt_flags = CFS_BACKFS_NFSV4; 433 if (cfs_nfsv4_build_opts(optionp, 434 cfs_nfsv4ops) != 0) { 435 nfsvers_error = TRUE; 436 goto clean_backmnt; 437 } 438 } 439 break; 440 441 case 4: 442 /* 443 * overwrite old option flags with NFSv4 flag. 444 * Note that will also operate in strict 445 * consistency mode. Clean up the option string 446 * to get rid of the cachefs-specific options 447 * to be in sync with the opt flags, otherwise 448 * these can make it into the mnttab and cause 449 * problems (esp. the disconnected option). 450 */ 451 margs.cfs_options.opt_flags = CFS_BACKFS_NFSV4; 452 if (cfs_nfsv4_build_opts(optionp, cfs_nfsv4ops) != 0) { 453 nfsvers_error = TRUE; 454 goto clean_backmnt; 455 } 456 break; 457 458 default: 459 /* error, unknown version */ 460 nfsvers_error = TRUE; 461 goto clean_backmnt; 462 } 463 } 464 465 /* 466 * Grab server name from special file arg if it is there or set 467 * server name to "server unknown". 468 */ 469 margs.cfs_hostname = servname; 470 strncpy(servname, specp, sizeof (servname)); 471 servname[sizeof (servname) - 1] = '\0'; 472 strp = strchr(servname, ':'); 473 if (strp == NULL) { 474 margs.cfs_hostname = "server unknown"; 475 margs.cfs_backfsname = specp; 476 } else { 477 *strp = '\0'; 478 /* 479 * The rest of the special file arg is the name of 480 * the back filesystem. 481 */ 482 strp++; 483 margs.cfs_backfsname = strp; 484 } 485 486 /* mount the cache file system */ 487 xx = mount((margs.cfs_backfs != NULL) ? margs.cfs_backfs : "nobackfs", 488 mntp, mflag | MS_DATA, MNTTYPE_CFS, 489 &margs, sizeof (margs), 490 (cfs_nfsv4ops[0] == '\0' ? mops : cfs_nfsv4ops), 491 MAX_MNTOPT_STR); 492 clean_backmnt: 493 if (xx == -1 || nfsvers_error) { 494 if (nfsvers_error) { 495 pr_err(gettext("nfs version error.")); 496 } else if (errno == ESRCH) { 497 pr_err(gettext("mount failed, options do not match.")); 498 } else if ((errno == EAGAIN) && (margs.cfs_backfs == NULL)) { 499 pr_err(gettext("mount failed, server not responding.")); 500 } else { 501 pr_err(gettext("mount failed %s"), strerror(errno)); 502 } 503 504 /* try to unmount the back file system if we mounted it */ 505 if (mounted) { 506 xx = 1; 507 newargv[xx++] = "umount"; 508 newargv[xx++] = margs.cfs_backfs; 509 newargv[xx++] = NULL; 510 511 /* fork */ 512 if ((pid = fork()) == -1) { 513 pr_err(gettext("could not fork: %s"), 514 strerror(errno)); 515 cachefs_dir_unlock(lockid); 516 return (1); 517 } 518 519 /* if the child */ 520 if (pid == 0) { 521 /* do the unmount */ 522 doexec(backfstypep, newargv, "umount"); 523 } 524 525 /* else if the parent */ 526 else { 527 wait(0); 528 } 529 rmdir(margs.cfs_backfs); 530 } 531 532 cachefs_dir_unlock(lockid); 533 return (1); 534 } 535 536 /* release the lock on the cache directory */ 537 cachefs_dir_unlock(lockid); 538 539 /* record the mount information in the fscache directory */ 540 record_mount(mntp, specp, margs.cfs_backfs, backfstypep, 541 margs.cfs_cachedir, margs.cfs_cacheid, 542 (cfs_nfsv4ops[0] == '\0' ? optionp : cfs_nfsv4ops), reducep); 543 544 /* notify the daemon of the mount */ 545 if (notify) 546 daemon_notify(margs.cfs_cachedir, margs.cfs_cacheid); 547 548 /* update mnttab file if necessary */ 549 if (!nomnttab) { 550 /* 551 * If we added the back file system, tag it with ignore, 552 * however, don't fail the mount after its done 553 * if the tag can't be added (eg., this would cause 554 * automounter problems). 555 */ 556 if (mounted) { 557 FILE *mt; 558 struct extmnttab mnt; 559 560 if ((mt = fopen(MNTTAB, "r")) == NULL) 561 return (1); 562 while (getextmntent(mt, &mnt, sizeof (mnt)) != -1) { 563 if (mnt.mnt_mountp != NULL && 564 strcmp(margs.cfs_backfs, 565 mnt.mnt_mountp) == 0) { 566 /* found it, do tag ioctl */ 567 mtdesc.mtd_major = mnt.mnt_major; 568 mtdesc.mtd_minor = mnt.mnt_minor; 569 mtdesc.mtd_mntpt = margs.cfs_backfs; 570 mtdesc.mtd_tag = MNTOPT_IGNORE; 571 572 (void) ioctl(fileno(mt), 573 MNTIOC_SETTAG, &mtdesc); 574 break; 575 } 576 } 577 fclose(mt); 578 } 579 } 580 581 /* return success */ 582 return (0); 583 } 584 585 586 /* 587 * 588 * usage 589 * 590 * Description: 591 * Prints a short usage message. 592 * Arguments: 593 * msgp message to include with the usage message 594 * Returns: 595 * Preconditions: 596 */ 597 598 void 599 usage(char *msgp) 600 { 601 if (msgp) { 602 pr_err(gettext("%s"), msgp); 603 } 604 605 fprintf(stderr, 606 gettext("Usage: mount -F cachefs [generic options] " 607 "-o backfstype=file_system_type[FSTypespecific_options] " 608 "special mount_point\n")); 609 } 610 611 /* 612 * 613 * pr_err 614 * 615 * Description: 616 * Prints an error message to stderr. 617 * Arguments: 618 * fmt printf style format 619 * ... arguments for fmt 620 * Returns: 621 * Preconditions: 622 * precond(fmt) 623 */ 624 625 void 626 pr_err(char *fmt, ...) 627 { 628 va_list ap; 629 630 va_start(ap, fmt); 631 (void) fprintf(stderr, gettext("mount -F cachefs: ")); 632 (void) vfprintf(stderr, fmt, ap); 633 (void) fprintf(stderr, "\n"); 634 va_end(ap); 635 } 636 637 /* 638 * 639 * set_cfs_args 640 * 641 * Description: 642 * Parse the comma delimited set of options specified by optionp 643 * and puts the results in margsp, mflagp, and backfstypepp. 644 * A string is constructed of options which are not specific to 645 * cfs and is placed in reducepp. 646 * Pointers to strings are invalid if this routine is called again. 647 * No initialization is done on margsp, mflagp, or backfstypepp. 648 * Arguments: 649 * optionp string of comma delimited options 650 * margsp option results for the mount dataptr arg 651 * mflagp option results for the mount mflag arg 652 * backfstypepp set to name of back file system type 653 * reducepp set to the option string without cfs specific options 654 * Returns: 655 * Returns 0 for success, -1 for an error. 656 * Preconditions: 657 * precond(optionp) 658 * precond(margsp) 659 * precond(mflagp) 660 * precond(backfstypepp) 661 * precond(reducepp) 662 */ 663 664 int 665 set_cfs_args(char *optionp, struct cachefs_mountargs *margsp, int *mflagp, 666 char **backfstypepp, char **reducepp, int *notifyp, int *nfsv3pass) 667 { 668 static char *optstrp = NULL; 669 static char *reducep = NULL; 670 char *savep, *strp, *valp; 671 int badopt; 672 int ret; 673 int o_backpath = 0; 674 int o_writemode = 0; 675 int xx; 676 uint_t yy; 677 struct stat64 sinfo; 678 char *pbuf; 679 680 /* free up any previous options */ 681 free(optstrp); 682 optstrp = NULL; 683 free(reducep); 684 reducep = NULL; 685 686 /* make a copy of the options so we can modify it */ 687 optstrp = strp = strdup(optionp); 688 reducep = malloc(strlen(optionp) + 1000); 689 if ((strp == NULL) || (reducep == NULL)) { 690 pr_err(gettext("out of memory")); 691 return (-1); 692 } 693 *reducep = '\0'; 694 695 /* parse the options */ 696 badopt = 0; 697 ret = 0; 698 while (*strp) { 699 savep = strp; 700 switch (getsubopt(&strp, cfs_opts, &valp)) { 701 702 case CFSOPT_BACKFSTYPE: 703 if (valp == NULL) 704 badopt = 1; 705 else 706 *backfstypepp = valp; 707 break; 708 709 case CFSOPT_CACHEDIR: 710 if (valp == NULL) 711 badopt = 1; 712 else { 713 margsp->cfs_cachedir = valp; 714 if (valp[0] != '/') { 715 pbuf = (char *)malloc(MAXPATHLEN + 716 strlen(valp) + 3); 717 if (pbuf == NULL) { 718 pr_err(gettext("out of memory")); 719 badopt = 1; 720 break; 721 } 722 if (getcwd(pbuf, MAXPATHLEN+1) == NULL) { 723 pr_err(gettext("cachedir too long")); 724 badopt = 1; 725 break; 726 } 727 if (pbuf[strlen(pbuf)-1] != '/') 728 strcat(pbuf, "/"); 729 strcat(pbuf, valp); 730 margsp->cfs_cachedir = pbuf; 731 } 732 } 733 break; 734 735 case CFSOPT_CACHEID: 736 if (valp == NULL) { 737 badopt = 1; 738 break; 739 } 740 741 if (strlen(valp) >= (size_t)C_MAX_MOUNT_FSCDIRNAME) { 742 pr_err(gettext("cacheid too long")); 743 badopt = 1; 744 break; 745 } 746 747 memset(margsp->cfs_cacheid, 0, C_MAX_MOUNT_FSCDIRNAME); 748 strcpy(margsp->cfs_cacheid, valp); 749 break; 750 751 case CFSOPT_BACKPATH: 752 if (valp == NULL) 753 badopt = 1; 754 else { 755 margsp->cfs_backfs = valp; 756 o_backpath = 1; 757 } 758 break; 759 760 case CFSOPT_WRITEAROUND: 761 margsp->cfs_options.opt_flags |= CFS_WRITE_AROUND; 762 o_writemode++; 763 break; 764 765 case CFSOPT_NONSHARED: 766 margsp->cfs_options.opt_flags |= CFS_NONSHARED; 767 o_writemode++; 768 break; 769 770 case CFSOPT_NOCONST: 771 margsp->cfs_options.opt_flags |= CFS_NOCONST_MODE; 772 break; 773 774 case CFSOPT_CODCONST: 775 margsp->cfs_options.opt_flags |= CFS_CODCONST_MODE; 776 break; 777 778 case CFSOPT_LOCALACCESS: 779 margsp->cfs_options.opt_flags &= ~CFS_ACCESS_BACKFS; 780 break; 781 782 case CFSOPT_NOSETSEC: 783 margsp->cfs_options.opt_flags |= CFS_NOACL; 784 break; 785 786 case CFSOPT_LLOCK: 787 margsp->cfs_options.opt_flags |= CFS_LLOCK; 788 strcat(reducep, ","); 789 strcat(reducep, savep); 790 break; 791 792 case CFSOPT_REMOUNT: 793 *mflagp |= MS_REMOUNT; 794 break; 795 796 case CFSOPT_SLIDE: 797 margsp->cfs_options.opt_flags |= CFS_SLIDE; 798 break; 799 800 case CFSOPT_FGSIZE: 801 if (bad(valp)) 802 badopt = 1; 803 else 804 margsp->cfs_options.opt_fgsize = atoi(valp); 805 break; 806 807 case CFSOPT_POPSIZE: 808 if (bad(valp)) 809 badopt = 1; 810 else 811 margsp->cfs_options.opt_popsize = 812 atoi(valp) * 1024; 813 break; 814 815 case CFSOPT_ACREGMIN: 816 if (bad(valp)) 817 badopt = 1; 818 else 819 margsp->cfs_acregmin = atoi(valp); 820 break; 821 822 case CFSOPT_ACREGMAX: 823 if (bad(valp)) 824 badopt = 1; 825 else 826 margsp->cfs_acregmax = atoi(valp); 827 break; 828 829 case CFSOPT_ACDIRMIN: 830 if (bad(valp)) 831 badopt = 1; 832 else 833 margsp->cfs_acdirmin = atoi(valp); 834 break; 835 836 case CFSOPT_ACDIRMAX: 837 if (bad(valp)) 838 badopt = 1; 839 else 840 margsp->cfs_acdirmax = atoi(valp); 841 break; 842 843 case CFSOPT_ACTIMEO: 844 if (bad(valp)) 845 badopt = 1; 846 else { 847 yy = atoi(valp); 848 margsp->cfs_acregmin = yy; 849 margsp->cfs_acregmax = yy; 850 margsp->cfs_acdirmin = yy; 851 margsp->cfs_acdirmax = yy; 852 } 853 /* 854 * Note that we do not pass the actimeo options 855 * to the back file system. This change was 856 * made for Chart. Chart needs noac or actimeo=0 857 * so it makes no sense to pass these options on. 858 * In theory it should be okay to not pass these 859 * options on for regular cachefs mounts since 860 * cachefs perform the required attribute caching. 861 */ 862 break; 863 864 #if 0 865 case CFSOPT_LAZYMOUNT: 866 margsp->cfs_options.opt_flags |= CFS_LAZYMOUNT; 867 break; 868 #endif 869 870 case CFSOPT_DISCONNECTABLE: 871 case CFSOPT_SNR: 872 margsp->cfs_options.opt_flags |= CFS_DISCONNECTABLE; 873 break; 874 875 case CFSOPT_NOFILL: 876 margsp->cfs_options.opt_flags |= CFS_NOFILL; 877 break; 878 879 case CFSOPT_SOFT: 880 margsp->cfs_options.opt_flags |= CFS_SOFT; 881 break; 882 883 case CFSOPT_NONOTIFY: 884 *notifyp = 0; 885 break; 886 887 #ifdef CFS_NFSV3_PASSTHROUGH 888 case CFSOPT_NFSV3PASSTHROUGH: 889 *nfsv3pass = 1; 890 break; 891 #endif /* CFS_NFSV3_PASSTHROUGH */ 892 893 default: 894 /* 895 * unknown or vfs layer option, save for the back 896 * file system 897 */ 898 strcat(reducep, ","); 899 strcat(reducep, savep); 900 break; 901 } 902 903 /* if a lexical error occurred */ 904 if (badopt) { 905 pr_err(gettext("invalid argument to option: \"%s\""), 906 savep); 907 badopt = 0; 908 ret = -1; 909 } 910 } 911 912 /* 913 * Should mount backfs soft if disconnectable & non-shared options 914 * are used. NFS soft option allows reads and writes to TIMEOUT 915 * when the server is not responding, which is crucial for 916 * disconnectable option to work all the time in non-shared mode. 917 * 918 * Should mount backfs semisoft if disconnectable & write-around 919 * are used. NFS semisoft option allows reads to TIMEOUT and 920 * write to block when the server is not responding, which is 921 * good for write around option because it is shared. 922 * 923 * Since disconnectable and strict options are conflicting, 924 * when disconnectable option is used, default option is set to 925 * demandconst. 926 */ 927 928 if (margsp->cfs_options.opt_flags & (CFS_DISCONNECTABLE | CFS_SOFT)) 929 if (margsp->cfs_options.opt_flags & CFS_NONSHARED) { 930 strcat(reducep, ",soft,noprint"); 931 margsp->cfs_options.opt_flags |= CFS_CODCONST_MODE; 932 } 933 else 934 strcat(reducep, ",semisoft,noprint"); 935 936 if (!(margsp->cfs_options.opt_flags & CFS_DISCONNECTABLE)) { 937 /* not snr, no need to notify the cachefsd */ 938 *notifyp = 0; 939 } 940 941 /* additional nfs options needed so disconnectable will work */ 942 if (margsp->cfs_options.opt_flags & CFS_DISCONNECTABLE) { 943 /* 944 * retry=0 so cachefs can mount if nfs mount fails 945 * even with this nfs takes 3 minutes to give up 946 * actimeo=0 because NFS does not pick up new ctime after 947 * rename 948 */ 949 strcat(reducep, ",retry=0"); 950 if (margsp->cfs_options.opt_flags & CFS_NONSHARED) 951 strcat(reducep, ",actimeo=0"); 952 } 953 954 /* check for conflicting options */ 955 xx = margsp->cfs_options.opt_flags; 956 if (o_backpath & (xx & CFS_DISCONNECTABLE)) { 957 pr_err(gettext("backpath cannot be used with disconnectable")); 958 ret = -1; 959 } 960 if (margsp->cfs_acregmin > margsp->cfs_acregmax) { 961 pr_err(gettext("acregmin cannot be greater than acregmax")); 962 ret = -1; 963 } 964 if (margsp->cfs_acdirmin > margsp->cfs_acdirmax) { 965 pr_err(gettext("acdirmin cannot be greater than acdirmax")); 966 ret = -1; 967 } 968 969 xx = CFS_NOCONST_MODE | CFS_CODCONST_MODE; 970 if ((margsp->cfs_options.opt_flags & xx) == xx) { 971 pr_err(gettext("only one of noconst and demandconst" 972 " may be specified")); 973 ret = -1; 974 } 975 976 if (o_writemode > 1) { 977 pr_err(gettext( 978 "only one of write-around or non-shared" 979 " may be specified")); 980 ret = -1; 981 } 982 983 /* if an error occured */ 984 if (ret) 985 return (-1); 986 987 /* if there are any options which are not mount specific */ 988 if (*reducep) 989 *reducepp = reducep + 1; 990 else 991 *reducepp = NULL; 992 993 /* return success */ 994 return (0); 995 } 996 997 /* 998 * 999 * get_mount_point 1000 * 1001 * Description: 1002 * Makes a suitable mount point for the back file system. 1003 * The name of the mount point created is stored in a malloced 1004 * buffer in pathpp 1005 * Arguments: 1006 * cachedirp the name of the cache directory 1007 * specp the special name of the device for the file system 1008 * pathpp where to store the mount point 1009 * Returns: 1010 * Returns 0 for success, -1 for an error. 1011 * Preconditions: 1012 * precond(cachedirp) 1013 * precond(specp) 1014 * precond(pathpp) 1015 */ 1016 1017 int 1018 get_mount_point(char *cachedirp, char *specp, char **pathpp) 1019 { 1020 char *strp; 1021 char *namep; 1022 struct stat64 stat1, stat2; 1023 int xx; 1024 int index; 1025 int max; 1026 1027 /* make a copy of the special device name */ 1028 specp = strdup(specp); 1029 if (specp == NULL) { 1030 pr_err(gettext("out of memory")); 1031 return (-1); 1032 } 1033 1034 /* convert the special device name into a file name */ 1035 strp = specp; 1036 while (strp = strchr(strp, '/')) { 1037 *strp = '_'; 1038 } 1039 1040 /* get some space for the path name */ 1041 strp = malloc(MAXPATHLEN); 1042 if (strp == NULL) { 1043 pr_err(gettext("out of memory")); 1044 return (-1); 1045 } 1046 1047 /* see if the mount directory is valid */ 1048 /* backfs can contain large files */ 1049 sprintf(strp, "%s/%s", cachedirp, BACKMNT_NAME); 1050 xx = stat64(strp, &stat1); 1051 if ((xx == -1) || !S_ISDIR(stat1.st_mode)) { 1052 pr_err(gettext("%s is not a valid cache."), strp); 1053 return (-1); 1054 } 1055 1056 /* find a directory name we can use */ 1057 max = 10000; 1058 namep = strp + strlen(strp); 1059 for (index = 1; index < max; index++) { 1060 1061 /* construct a directory name to consider */ 1062 if (index == 1) 1063 sprintf(namep, "/%s", specp); 1064 else 1065 sprintf(namep, "/%s_%d", specp, index); 1066 1067 /* try to create the directory */ 1068 xx = mkdir(strp, 0755); 1069 if (xx == 0) { 1070 /* done if the create succeeded */ 1071 break; 1072 } 1073 } 1074 1075 /* if the search failed */ 1076 if (index >= max) { 1077 pr_err(gettext("could not create a directory")); 1078 return (-1); 1079 } 1080 1081 /* return success */ 1082 *pathpp = strp; 1083 return (0); 1084 } 1085 1086 1087 int 1088 dobackmnt(struct cachefs_mountargs *margsp, char *reducep, char *specp, 1089 char *backfstypep, char *mynamep, int readonly) 1090 { 1091 int xx; 1092 pid_t pid; 1093 char *newargv[20]; 1094 int stat_loc; 1095 1096 /* get a suitable mount point */ 1097 xx = get_mount_point(margsp->cfs_cachedir, specp, &margsp->cfs_backfs); 1098 if (xx) 1099 return (1); 1100 1101 /* construct argument list for mounting the back file system */ 1102 xx = 1; 1103 newargv[xx++] = "mount"; 1104 if (readonly) 1105 newargv[xx++] = "-r"; 1106 if (nomnttab) 1107 newargv[xx++] = "-m"; 1108 if (quiet) 1109 newargv[xx++] = "-q"; 1110 if (reducep) { 1111 newargv[xx++] = "-o"; 1112 newargv[xx++] = reducep; 1113 } 1114 newargv[xx++] = specp; 1115 newargv[xx++] = margsp->cfs_backfs; 1116 newargv[xx++] = NULL; 1117 1118 /* fork */ 1119 if ((pid = fork()) == -1) { 1120 pr_err(gettext("could not fork %s"), strerror(errno)); 1121 return (1); 1122 } 1123 1124 /* if the child */ 1125 if (pid == 0) { 1126 /* do the mount */ 1127 doexec(backfstypep, newargv, mynamep); 1128 } 1129 1130 /* else if the parent */ 1131 else { 1132 /* wait for the child to exit */ 1133 if (wait(&stat_loc) == -1) { 1134 pr_err(gettext("wait failed %s"), strerror(errno)); 1135 return (1); 1136 } 1137 1138 if (!WIFEXITED(stat_loc)) { 1139 pr_err(gettext("back mount did not exit")); 1140 return (1); 1141 } 1142 1143 xx = WEXITSTATUS(stat_loc); 1144 if (xx) { 1145 pr_err(gettext("back mount failed")); 1146 return (xx); 1147 } 1148 } 1149 1150 return (0); 1151 } 1152 1153 /* 1154 * 1155 * doexec 1156 * 1157 * Description: 1158 * Execs the specified program with the specified command line arguments. 1159 * This function never returns. 1160 * Arguments: 1161 * fstype type of file system 1162 * newargv command line arguments 1163 * progp name of program to exec 1164 * Returns: 1165 * Preconditions: 1166 * precond(fstype) 1167 * precond(newargv) 1168 */ 1169 1170 void 1171 doexec(char *fstype, char *newargv[], char *progp) 1172 { 1173 char full_path[PATH_MAX]; 1174 char alter_path[PATH_MAX]; 1175 char *vfs_path = VFS_PATH; 1176 char *alt_path = ALT_PATH; 1177 1178 /* build the full pathname of the fstype dependent command. */ 1179 sprintf(full_path, "%s/%s/%s", vfs_path, fstype, progp); 1180 sprintf(alter_path, "%s/%s/%s", alt_path, fstype, progp); 1181 1182 /* if the program exists */ 1183 if (access(full_path, 0) == 0) { 1184 /* invoke the program */ 1185 execv(full_path, &newargv[1]); 1186 1187 /* if wrong permissions */ 1188 if (errno == EACCES) { 1189 pr_err(gettext("cannot execute %s %s"), 1190 full_path, strerror(errno)); 1191 } 1192 1193 /* if it did not work and the shell might make it */ 1194 if (errno == ENOEXEC) { 1195 newargv[0] = "sh"; 1196 newargv[1] = full_path; 1197 execv("/sbin/sh", &newargv[0]); 1198 } 1199 } 1200 1201 /* try the alternate path */ 1202 execv(alter_path, &newargv[1]); 1203 1204 /* if wrong permissions */ 1205 if (errno == EACCES) { 1206 pr_err(gettext("cannot execute %s %s"), 1207 alter_path, strerror(errno)); 1208 } 1209 1210 /* if it did not work and the shell might make it */ 1211 if (errno == ENOEXEC) { 1212 newargv[0] = "sh"; 1213 newargv[1] = alter_path; 1214 execv("/sbin/sh", &newargv[0]); 1215 } 1216 1217 pr_err(gettext("operation not applicable to FSType %s"), fstype); 1218 exit(1); 1219 } 1220 1221 /* 1222 * 1223 * get_back_fsid 1224 * 1225 * Description: 1226 * Determines a unique identifier for the back file system. 1227 * Arguments: 1228 * specp the special file of the back fs 1229 * Returns: 1230 * Returns a malloc string which is the unique identifer 1231 * or NULL on failure. NULL is only returned if malloc fails. 1232 * Preconditions: 1233 * precond(specp) 1234 */ 1235 1236 char * 1237 get_back_fsid(char *specp) 1238 { 1239 return (strdup(specp)); 1240 } 1241 1242 /* 1243 * 1244 * get_cacheid 1245 * 1246 * Description: 1247 * Determines an identifier for the front file system cache. 1248 * The returned string points to a static buffer which is 1249 * overwritten on each call. 1250 * The length of the returned string is < C_MAX_MOUNT_FSCDIRNAME. 1251 * Arguments: 1252 * fsidp back file system id 1253 * mntp front file system mount point 1254 * Returns: 1255 * Returns a pointer to the string identifier, or NULL if the 1256 * identifier was overflowed. 1257 * Preconditions: 1258 * precond(fsidp) 1259 * precond(mntp) 1260 */ 1261 1262 char * 1263 get_cacheid(char *fsidp, char *mntp) 1264 { 1265 char *c1; 1266 static char buf[PATH_MAX]; 1267 char mnt_copy[PATH_MAX]; 1268 1269 /* strip off trailing space in mountpoint -- autofs fallout */ 1270 if (strlen(mntp) >= sizeof (mnt_copy)) 1271 return (NULL); 1272 (void) strcpy(mnt_copy, mntp); 1273 c1 = mnt_copy + strlen(mnt_copy) - 1; 1274 if (*c1 == ' ') 1275 *c1 = '\0'; 1276 1277 if ((strlen(fsidp) + strlen(mnt_copy) + 2) >= 1278 (size_t)C_MAX_MOUNT_FSCDIRNAME) 1279 return (NULL); 1280 1281 strcpy(buf, fsidp); 1282 strcat(buf, ":"); 1283 strcat(buf, mnt_copy); 1284 c1 = buf; 1285 while ((c1 = strpbrk(c1, "/")) != NULL) 1286 *c1 = '_'; 1287 return (buf); 1288 } 1289 1290 1291 /* 1292 * 1293 * check_cache 1294 * 1295 * Description: 1296 * Checks the cache we are about to use. 1297 * Arguments: 1298 * cachedirp cachedirectory to check 1299 * Returns: 1300 * Returns 0 for success, -1 for an error. 1301 * Preconditions: 1302 */ 1303 int 1304 check_cache(cachedirp) 1305 char *cachedirp; 1306 { 1307 char *fsck_argv[4]; 1308 int status = 0; 1309 pid_t pid; 1310 1311 fsck_argv[1] = "fsck"; 1312 fsck_argv[2] = cachedirp; 1313 fsck_argv[3] = NULL; 1314 1315 /* fork */ 1316 if ((pid = fork()) == -1) { 1317 pr_err(gettext("could not fork %s"), 1318 strerror(errno)); 1319 return (1); 1320 } 1321 1322 if (pid == 0) { 1323 /* do the fsck */ 1324 doexec("cachefs", fsck_argv, "fsck"); 1325 } else { 1326 /* wait for the child to exit */ 1327 if (wait(&status) == -1) { 1328 pr_err(gettext("wait failed %s"), 1329 strerror(errno)); 1330 return (1); 1331 } 1332 1333 if (!WIFEXITED(status)) { 1334 pr_err(gettext("cache fsck did not exit")); 1335 return (1); 1336 } 1337 1338 if (WEXITSTATUS(status) != 0) { 1339 pr_err(gettext("cache fsck mount failed")); 1340 return (1); 1341 } 1342 } 1343 return (0); 1344 } 1345 1346 /* 1347 * 1348 * record_mount 1349 * 1350 * Description: 1351 * Records mount information in a file in the fscache directory. 1352 * Arguments: 1353 * Returns: 1354 * Preconditions: 1355 */ 1356 1357 void 1358 record_mount(char *mntp, char *specp, char *backfsp, char *backfstypep, 1359 char *cachedirp, char *cacheidp, char *optionp, char *reducep) 1360 { 1361 char buf[MAXPATHLEN*2]; 1362 FILE *fout; 1363 time_t tval; 1364 1365 tval = time(NULL); 1366 1367 /* this file is < 2GB */ 1368 sprintf(buf, "%s/%s/%s", cachedirp, cacheidp, CACHEFS_MNT_FILE); 1369 fout = fopen(buf, "w"); 1370 if (fout == NULL) { 1371 pr_err(gettext("could not open %s, %d"), buf, errno); 1372 return; 1373 } 1374 1375 fprintf(fout, "cachedir: %s\n", cachedirp); 1376 fprintf(fout, "mnt_point: %s\n", mntp); 1377 if (specp) { 1378 fprintf(fout, "special: %s\n", specp); 1379 } 1380 if (backfsp) 1381 fprintf(fout, "backpath: %s\n", backfsp); 1382 fprintf(fout, "backfstype: %s\n", backfstypep); 1383 fprintf(fout, "cacheid: %s\n", cacheidp); 1384 fprintf(fout, "cachefs_options: %s\n", optionp); 1385 if (reducep) 1386 fprintf(fout, "backfs_options: %s\n", reducep); 1387 fprintf(fout, "mount_time: %u\n", tval); 1388 1389 fclose(fout); 1390 } 1391 1392 int 1393 daemon_notify(char *cachedirp, char *cacheidp) 1394 { 1395 CLIENT *clnt; 1396 enum clnt_stat retval; 1397 int ret; 1398 int xx; 1399 int result; 1400 char *hostp; 1401 struct utsname info; 1402 struct cachefsd_fs_mounted args; 1403 1404 /* get the host name */ 1405 xx = uname(&info); 1406 if (xx == -1) { 1407 pr_err(gettext("cannot get host name, errno %d"), errno); 1408 return (1); 1409 } 1410 hostp = info.nodename; 1411 1412 /* creat the connection to the daemon */ 1413 clnt = clnt_create(hostp, CACHEFSDPROG, CACHEFSDVERS, "local"); 1414 if (clnt == NULL) { 1415 pr_err(gettext("cachefsd is not running")); 1416 return (1); 1417 } 1418 1419 args.mt_cachedir = cachedirp; 1420 args.mt_cacheid = cacheidp; 1421 retval = cachefsd_fs_mounted_1(&args, NULL, clnt); 1422 if (retval != RPC_SUCCESS) { 1423 clnt_perror(clnt, gettext("cachefsd is not responding")); 1424 clnt_destroy(clnt); 1425 return (1); 1426 } 1427 1428 ret = 0; 1429 1430 clnt_destroy(clnt); 1431 1432 return (ret); 1433 } 1434 1435 /* returns 0 if the server is alive, -1 if an error */ 1436 int 1437 pingserver(char *backmntp) 1438 { 1439 CLIENT *clnt; 1440 static struct timeval TIMEOUT = { 25, 0 }; 1441 enum clnt_stat retval; 1442 int ret; 1443 int xx; 1444 char *hostp; 1445 char buf[MAXPATHLEN]; 1446 char *pc; 1447 1448 /* get the host name */ 1449 strcpy(buf, backmntp); 1450 pc = strchr(buf, ':'); 1451 if (pc == NULL) { 1452 /* no host name, pretend it works */ 1453 return (0); 1454 } 1455 *pc = '\0'; 1456 hostp = buf; 1457 1458 /* create the connection to the mount daemon */ 1459 clnt = clnt_create(hostp, NFS_PROGRAM, NFS_VERSION, "udp"); 1460 if (clnt == NULL) { 1461 return (-1); 1462 } 1463 1464 ret = 0; 1465 1466 /* see if the mountd responds */ 1467 retval = clnt_call(clnt, 0, xdr_void, NULL, xdr_void, NULL, 1468 TIMEOUT); 1469 if (retval != RPC_SUCCESS) { 1470 ret = -1; 1471 } 1472 1473 clnt_destroy(clnt); 1474 1475 return (ret); 1476 } 1477 1478 /* 1479 * first_time_ab : first time after boot - returns non-zero value 1480 * if the cachedir is being used for the first time 1481 * after the system reboot, otherwise zero. 1482 */ 1483 int 1484 first_time_ab(char *buf) 1485 { 1486 struct stat sinfo; 1487 char name[MAXPATHLEN]; 1488 int ufd; 1489 time32_t btime; 1490 1491 sprintf(name, "%s/%s", buf, CACHEFS_UNMNT_FILE); 1492 if (stat(name, &sinfo) != 0) 1493 return (1); 1494 if (sinfo.st_size == 0) 1495 return (1); 1496 if ((ufd = open(name, O_RDONLY)) == -1) 1497 return (1); 1498 if (read(ufd, &btime, sizeof (time32_t)) == -1) 1499 return (1); 1500 close(ufd); 1501 if (get_boottime() != btime) 1502 return (1); 1503 return (0); 1504 } 1505 1506 /* 1507 * cachefs_get_back_nfsvers 1508 * 1509 * Returns: nfs version 1510 * 1511 * Params: 1512 * cfs_backfs - backfile system mountpoint 1513 * nomnttab - mnttab entry does not exist 1514 * 1515 * Uses the kstat interface to extract the nfs version for 1516 * the mount. 1517 */ 1518 uint32_t 1519 cachefs_get_back_nfsvers(char *cfs_backfs, int nomnttab) 1520 { 1521 kstat_ctl_t *kc = NULL; 1522 FILE *mnttab = NULL; 1523 struct extmnttab mnt; 1524 kstat_t *ksp; 1525 dev_t my_fsid = NODEV; 1526 struct mntinfo_kstat mik; 1527 uint32_t nfsvers = 0; 1528 struct stat64 st; 1529 1530 /* 1531 * Initialize kernel statistics facility. 1532 */ 1533 if ((kc = kstat_open()) == NULL) { 1534 pr_err(gettext("kstat_open() can't open /dev/kstat: %s"), 1535 strerror(errno)); 1536 goto end; 1537 } 1538 1539 /* 1540 * Locate the mount information in the mnttab if the nomnttab 1541 * flag is not set, otherwise look for the entry by doing 1542 * stat'ting the mountpoint. 1543 */ 1544 if (!nomnttab) { 1545 if ((mnttab = fopen(MNTTAB, "r")) == NULL) { 1546 pr_err(gettext("can't open /etc/mnttab: %s"), 1547 strerror(errno)); 1548 goto end; 1549 } 1550 1551 while (getextmntent(mnttab, &mnt, sizeof (mnt)) != -1) { 1552 if (mnt.mnt_mountp == NULL || 1553 strcmp(cfs_backfs, mnt.mnt_mountp) != 0) { 1554 continue; 1555 } 1556 my_fsid = makedev(mnt.mnt_major, mnt.mnt_minor); 1557 break; 1558 } 1559 } 1560 1561 if (my_fsid == NODEV) { 1562 if (stat64(cfs_backfs, &st) == -1) { 1563 pr_err(gettext("can't stat mountpoint: %s"), 1564 strerror(errno)); 1565 goto end; 1566 } else { 1567 my_fsid = st.st_dev; 1568 } 1569 1570 } 1571 1572 /* 1573 * Walk the kstat control structures to locate the 1574 * structure that describes the nfs module/mntinfo 1575 * statistics for the mounted backfilesystem. 1576 */ 1577 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) { 1578 1579 if (ksp->ks_type != KSTAT_TYPE_RAW) 1580 continue; 1581 if (strcmp(ksp->ks_module, "nfs") != 0) 1582 continue; 1583 if (strcmp(ksp->ks_name, "mntinfo") != 0) 1584 continue; 1585 if ((my_fsid & MAXMIN) != ksp->ks_instance) 1586 continue; 1587 1588 /* 1589 * At this point we have located the 1590 * kstat info for the mount, read the 1591 * statistics and return version info. 1592 */ 1593 if (kstat_read(kc, ksp, &mik) == -1) { 1594 pr_err(gettext("kstat_read() can't read %s/%s: %s"), 1595 ksp->ks_module, ksp->ks_name, strerror(errno)); 1596 goto end; 1597 } 1598 1599 nfsvers = mik.mik_vers; 1600 break; 1601 } 1602 1603 end: 1604 if (kc) 1605 kstat_close(kc); 1606 if (mnttab) 1607 fclose(mnttab); 1608 1609 return (nfsvers); 1610 } 1611 1612 /* 1613 * cfs_nfsv4_build_opts 1614 * 1615 * Returns: 0 on success, -1 on failure 1616 * 1617 * Params: 1618 * optionp - original option pointer 1619 * cfs_nfsv4ops - modified options for nfsv4 cachefs mount 1620 * 1621 * Parse the comma delimited set of options specified by optionp 1622 * and clean out options that we don't want to use with NFSv4. 1623 */ 1624 int 1625 cfs_nfsv4_build_opts(char *optionp, char *cfs_nfsv4ops) 1626 { 1627 char *optstrp; 1628 char *strp; 1629 char *savep; 1630 char *valp; 1631 uint32_t first = TRUE; 1632 1633 /* Make a copy of the options so we can modify it */ 1634 optstrp = strp = strdup(optionp); 1635 if (strp == NULL) { 1636 pr_err(gettext("out of memory")); 1637 return (-1); 1638 } 1639 1640 /* Parse the options, cfs_nfsv4ops is initialized in main */ 1641 while (*strp) { 1642 savep = strp; 1643 switch (getsubopt(&strp, cfs_opts, &valp)) { 1644 1645 /* Ignore options that set cfs option flags */ 1646 case CFSOPT_WRITEAROUND: 1647 case CFSOPT_NONSHARED: 1648 case CFSOPT_NOCONST: 1649 case CFSOPT_CODCONST: 1650 case CFSOPT_LOCALACCESS: 1651 case CFSOPT_NOSETSEC: 1652 case CFSOPT_LLOCK: 1653 case CFSOPT_SLIDE: 1654 case CFSOPT_DISCONNECTABLE: 1655 case CFSOPT_SNR: 1656 case CFSOPT_NOFILL: 1657 case CFSOPT_SOFT: 1658 break; 1659 1660 default: 1661 /* 1662 * Copy in option for cachefs nfsv4 mount. 1663 */ 1664 snprintf(cfs_nfsv4ops, MAX_MNTOPT_STR, 1665 "%s%s%s", cfs_nfsv4ops, first ? "" : ",", 1666 savep); 1667 first = FALSE; 1668 break; 1669 } 1670 } 1671 free(optstrp); 1672 1673 return (0); 1674 } 1675