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