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
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.
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]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
33 * Cache FS admin utility.
49 #include <sys/param.h>
50 #include <sys/types.h>
52 #include <sys/statvfs.h>
54 #include <sys/mnttab.h>
55 #include <sys/fs/cachefs_fs.h>
56 #include <sys/fs/cachefs_dir.h>
57 #include <sys/utsname.h>
60 #include "../common/subr.h"
61 #include "../common/cachefsd.h"
63 char *cfsadmin_opts
[] = {
64 #define COPT_MAXBLOCKS 0
66 #define COPT_MINBLOCKS 1
68 #define COPT_THRESHBLOCKS 2
71 #define COPT_MAXFILES 3
73 #define COPT_MINFILES 4
75 #define COPT_THRESHFILES 5
78 #define COPT_MAXFILESIZE 6
81 #define COPT_HIBLOCKS 7
83 #define COPT_LOWBLOCKS 8
85 #define COPT_HIFILES 9
87 #define COPT_LOWFILES 10
92 #define bad(val) ((val) == NULL || !isdigit(*(val)))
94 /* numbers must be valid percentages ranging from 0 to 100 */
95 #define badpercent(val) \
96 ((val) == NULL || !isdigit(*(val)) || \
97 atoi((val)) < 0 || atoi((val)) > 100)
99 /* forward references */
100 void usage(char *msg
);
101 void pr_err(char *fmt
, ...);
102 int cfs_get_opts(char *oarg
, struct cachefs_user_values
*uvp
);
103 int update_cachelabel(char *dirp
, char *optionp
);
104 void user_values_defaults(struct cachefs_user_values
*uvp
);
105 int check_user_values_for_sanity(const struct cachefs_user_values
*uvp
);
106 int cache_stats(char *dirp
);
107 int resource_file_grow(char *dirp
, int oldcnt
, int newcnt
);
108 int resource_file_dirty(char *dirp
);
109 void simulate_disconnection(char *namep
, int disconnect
);
116 * Main routine for the cfsadmin program.
118 * argc number of command line arguments
119 * argv command line arguments
121 * Returns 0 for failure, > 0 for an error.
126 main(int argc
, char **argv
)
145 priv_set_t
*priv_needed
, *priv_effective
;
147 (void) setlocale(LC_ALL
, "");
149 #if !defined(TEXT_DOMAIN)
150 #define TEXT_DOMAIN "SYS_TEST"
152 (void) textdomain(TEXT_DOMAIN
);
154 /* set defaults for command line options */
165 /* parse the command line arguments */
166 while ((c
= getopt(argc
, argv
, "cCDuo:d:sl")) != EOF
) {
169 case 'c': /* create */
174 * -C and -D are undocumented calls used
175 * to simulate disconnection on a file system.
177 case 'C': /* connect file system */
180 case 'D': /* disconnect file system */
184 case 'u': /* update */
188 case 'd': /* delete */
190 if (strcmp(optarg
, "all") == 0)
196 case 's': /* consistency on demand */
200 case 'l': /* list cache ids */
204 case 'o': /* options for update and create */
209 usage(gettext("illegal option"));
214 if ((cflag
+ dflag
+ lflag
+ sflag
+ uflag
+ Cflag
+ Dflag
) == 0) {
215 usage(gettext("no options specified"));
219 if (cflag
|| uflag
|| dflag
|| Cflag
|| Dflag
)
220 priv_needed
= priv_str_to_set("all", ",", NULL
);
221 if ((cflag
|| uflag
) && getuid() != 0) {
222 /* These options create files. We want them to be root owned */
223 pr_err(gettext("must be run by root"));
228 priv_needed
= priv_str_to_set("file_dac_search,file_dac_read",
232 priv_needed
= priv_str_to_set("sys_config", ",", NULL
);
234 priv_effective
= priv_allocset();
235 (void) getppriv(PRIV_EFFECTIVE
, priv_effective
);
236 if (priv_issubset(priv_needed
, priv_effective
) == 0) {
237 pr_err(gettext("Not privileged."));
240 priv_freeset(priv_effective
);
241 priv_freeset(priv_needed
);
243 if ((sflag
+ Cflag
+ Dflag
) == 0) {
244 /* make sure cachedir is specified */
245 if (argc
- 1 != optind
) {
246 usage(gettext("cache directory not specified"));
249 cachedir
= argv
[argc
-1];
251 /* make sure at least one mount point is specified */
252 if (argc
- 1 < optind
) {
253 usage(gettext("mount points not specified"));
258 /* make sure a reasonable set of flags were specified */
259 if ((cflag
+ uflag
+ dflag
+ sflag
+ lflag
+ Cflag
+ Dflag
) != 1) {
260 /* flags are mutually exclusive, at least one must be set */
262 "exactly one of -c, -u, -d, -s, -l must be specified"));
266 /* make sure -o specified with -c or -u */
267 if (optionp
&& !(cflag
|uflag
)) {
268 usage(gettext("-o can only be used with -c or -u"));
272 /* if creating a cache */
274 struct cachefs_user_values uv
;
275 struct cache_label clabel
;
277 /* get default cache paramaters */
278 user_values_defaults(&uv
);
280 /* parse the options if specified */
282 xx
= cfs_get_opts(optionp
, &uv
);
287 /* verify options are reasonable */
288 xx
= check_user_values_for_sanity(&uv
);
292 /* lock the cache directory non-shared */
293 lockid
= cachefs_dir_lock(cachedir
, 0);
295 /* quit if could not get the lock */
299 /* create the cache */
300 xx
= cachefs_create_cache(cachedir
, &uv
, &clabel
);
303 /* remove a partially created cache dir */
304 (void) cachefs_delete_all_cache(cachedir
);
306 cachefs_dir_unlock(lockid
);
309 cachefs_dir_unlock(lockid
);
312 /* else if updating resource parameters */
314 /* lock the cache directory non-shared */
315 lockid
= cachefs_dir_lock(cachedir
, 0);
317 /* quit if could not get the lock */
321 xx
= update_cachelabel(cachedir
, optionp
);
322 cachefs_dir_unlock(lockid
);
328 /* else if deleting a specific cacheID (or all caches) */
330 /* lock the cache directory non-shared */
331 lockid
= cachefs_dir_lock(cachedir
, 0);
333 /* quit if could not get the lock */
337 /* if the cache is in use */
338 if (cachefs_inuse(cachedir
)) {
339 pr_err(gettext("Cache %s is in use and "
340 "cannot be modified."), cachedir
);
341 cachefs_dir_unlock(lockid
);
346 xx
= cachefs_delete_all_cache(cachedir
);
348 /* mark resource file as dirty */
349 xx
= resource_file_dirty(cachedir
);
351 xx
= cachefs_delete_cache(cachedir
, cacheid
);
353 cachefs_dir_unlock(lockid
);
359 /* else if listing cache statistics */
361 xx
= cache_stats(cachedir
);
366 /* else if issuing a check event to cached file systems */
368 for (xx
= optind
; xx
< argc
; xx
++) {
373 /* else if simulating a disconnection */
375 for (xx
= optind
; xx
< argc
; xx
++) {
376 simulate_disconnection(argv
[xx
], 1);
380 /* else if connection after a simulated disconnection */
382 for (xx
= optind
; xx
< argc
; xx
++) {
383 simulate_disconnection(argv
[xx
], 0);
397 * Prints a usage message for this utility.
399 * msgp message to include with the usage message
408 fprintf(stderr
, gettext("cfsadmin: %s\n"), msgp
);
409 fprintf(stderr
, gettext(
410 "usage: cfsadmin -[cu] [-o parameter-list] cachedir\n"));
411 fprintf(stderr
, gettext(" cfsadmin -d [CacheID|all] cachedir\n"));
412 fprintf(stderr
, gettext(" cfsadmin -l cachedir\n"));
413 fprintf(stderr
, gettext(" cfsadmin -s [mntpnt1 ... | all]\n"));
421 * Prints an error message to stderr.
423 * fmt printf style format
424 * ... arguments for fmt
431 pr_err(char *fmt
, ...)
436 (void) fprintf(stderr
, gettext("cfsadmin: "));
437 (void) vfprintf(stderr
, fmt
, ap
);
438 (void) fprintf(stderr
, "\n");
447 * Decodes cfs options specified with -o.
448 * Only the fields referenced by the options are modified.
450 * oarg options from -o option
451 * uvp place to put options
453 * Returns 0 for success, -1 for an error.
460 cfs_get_opts(char *oarg
, struct cachefs_user_values
*uvp
)
462 char *optstr
, *opts
, *val
;
466 /* make a copy of the options because getsubopt modifies it */
467 optstr
= opts
= strdup(oarg
);
469 pr_err(gettext("no memory"));
473 /* process the options */
475 while (*opts
&& !badopt
) {
477 switch (getsubopt(&opts
, cfsadmin_opts
, &val
)) {
482 uvp
->uv_maxblocks
= atoi(val
);
488 uvp
->uv_minblocks
= atoi(val
);
490 case COPT_THRESHBLOCKS
:
494 uvp
->uv_threshblocks
= atoi(val
);
501 uvp
->uv_maxfiles
= atoi(val
);
507 uvp
->uv_minfiles
= atoi(val
);
509 case COPT_THRESHFILES
:
513 uvp
->uv_threshfiles
= atoi(val
);
516 case COPT_MAXFILESIZE
:
520 uvp
->uv_maxfilesize
= atoi(val
);
527 uvp
->uv_hiblocks
= atoi(val
);
533 uvp
->uv_lowblocks
= atoi(val
);
539 uvp
->uv_hifiles
= atoi(val
);
545 uvp
->uv_lowfiles
= atoi(val
);
548 /* if a bad option argument */
549 pr_err(gettext("Invalid option %s"), saveopts
);
554 /* if a bad value for an option, display an error message */
556 pr_err(gettext("invalid argument to option: \"%s\""),
560 /* free the duplicated option string */
563 /* return the result */
564 return (badopt
? -1 : 0);
572 * Changes the parameters of the cache_label.
573 * If optionp is NULL then the cache_label is set to
576 * dirp the name of the cache directory
577 * optionp comma delimited options
579 * Returns 0 for success and -1 for an error.
585 update_cachelabel(char *dirp
, char *optionp
)
587 char path
[CACHEFS_XMAXPATH
];
588 struct cache_label clabel_new
;
589 struct cache_label clabel_orig
;
590 struct cachefs_user_values uv_orig
, uv_new
;
593 /* if the cache is in use */
594 if (cachefs_inuse(dirp
)) {
595 pr_err(gettext("Cache %s is in use and cannot be modified."),
600 /* make sure we don't overwrite path */
601 if (strlen(dirp
) > (size_t)PATH_MAX
) {
602 pr_err(gettext("name of label file %s is too long."),
607 /* construct the pathname to the cach_label file */
608 sprintf(path
, "%s/%s", dirp
, CACHELABEL_NAME
);
610 /* read the current set of parameters */
611 xx
= cachefs_label_file_get(path
, &clabel_orig
);
613 pr_err(gettext("reading %s failed"), path
);
616 xx
= cachefs_label_file_vcheck(path
, &clabel_orig
);
618 pr_err(gettext("version mismatch on %s"), path
);
622 /* convert the cache_label to user values */
623 xx
= cachefs_convert_cl2uv(&clabel_orig
, &uv_orig
, dirp
);
628 /* if options were specified */
630 /* start with the original values */
633 /* parse the options */
634 xx
= cfs_get_opts(optionp
, &uv_new
);
639 /* verify options are reasonable */
640 xx
= check_user_values_for_sanity(&uv_new
);
646 /* else if options where not specified, get defaults */
648 user_values_defaults(&uv_new
);
651 /* convert user values to a cache_label */
652 xx
= cachefs_convert_uv2cl(&uv_new
, &clabel_new
, dirp
);
657 /* do not allow the cache size to shrink */
658 if (uv_orig
.uv_maxblocks
> uv_new
.uv_maxblocks
) {
659 pr_err(gettext("Cache size cannot be reduced,"
660 " maxblocks current %d%%, requested %d%%"),
661 uv_orig
.uv_maxblocks
, uv_new
.uv_maxblocks
);
664 if (clabel_orig
.cl_maxinodes
> clabel_new
.cl_maxinodes
) {
665 pr_err(gettext("Cache size cannot be reduced,"
666 " maxfiles current %d%% requested %d%%"),
667 uv_orig
.uv_maxfiles
, uv_new
.uv_maxfiles
);
671 /* write back the new values */
672 xx
= cachefs_label_file_put(path
, &clabel_new
);
674 pr_err(gettext("writing %s failed"), path
);
678 /* put the new values in the duplicate cache label file also */
679 sprintf(path
, "%s/%s.dup", dirp
, CACHELABEL_NAME
);
680 xx
= cachefs_label_file_put(path
, &clabel_new
);
682 pr_err(gettext("writing %s failed"), path
);
686 /* grow resouces file if necessary */
688 if (clabel_orig
.cl_maxinodes
!= clabel_new
.cl_maxinodes
) {
689 xx
= resource_file_grow(dirp
, clabel_orig
.cl_maxinodes
,
690 clabel_new
.cl_maxinodes
);
699 * user_values_defaults
702 * Sets default values in the cachefs_user_values object.
704 * uvp cachefs_user_values object to set values for
711 user_values_defaults(struct cachefs_user_values
*uvp
)
713 uvp
->uv_maxblocks
= 90;
714 uvp
->uv_minblocks
= 0;
715 uvp
->uv_threshblocks
= 85;
716 uvp
->uv_maxfiles
= 90;
717 uvp
->uv_minfiles
= 0;
718 uvp
->uv_threshfiles
= 85;
719 uvp
->uv_maxfilesize
= 3;
720 uvp
->uv_hiblocks
= 85;
721 uvp
->uv_lowblocks
= 75;
722 uvp
->uv_hifiles
= 85;
723 uvp
->uv_lowfiles
= 75;
728 * check_user_values_for_sanity
731 * Check the cachefs_user_values for sanity.
733 * uvp cachefs_user_values object to check
735 * Returns 0 if okay, -1 if not.
741 check_user_values_for_sanity(const struct cachefs_user_values
*uvp
)
747 if (uvp
->uv_lowblocks
>= uvp
->uv_hiblocks
) {
748 pr_err(gettext("lowblocks can't be >= hiblocks."));
751 if (uvp
->uv_lowfiles
>= uvp
->uv_hifiles
) {
752 pr_err(gettext("lowfiles can't be >= hifiles."));
756 /* XXX more conditions to check here? */
758 /* XXX make sure thresh values are between min and max values */
769 * Show each cache in the directory, cache resource statistics,
770 * and, for each fs in the cache, the name of the fs, and the
771 * cache resource parameters.
773 * dirp name of the cache directory
775 * Returns 0 for success, -1 for an error.
781 cache_stats(char *dirp
)
784 struct dirent64
*dep
;
785 char path
[CACHEFS_XMAXPATH
];
786 struct stat64 statinfo
;
789 struct cache_label clabel
;
790 struct cachefs_user_values uv
;
792 /* make sure cache dir name is not too long */
793 if (strlen(dirp
) > (size_t)PATH_MAX
) {
794 pr_err(gettext("path name %s is too long."), dirp
);
798 /* read the cache label file */
799 sprintf(path
, "%s/%s", dirp
, CACHELABEL_NAME
);
800 xx
= cachefs_label_file_get(path
, &clabel
);
802 pr_err(gettext("Reading %s failed."), path
);
805 xx
= cachefs_label_file_vcheck(path
, &clabel
);
807 pr_err(gettext("Version mismatch on %s."), path
);
811 /* convert the cache_label to user values */
812 xx
= cachefs_convert_cl2uv(&clabel
, &uv
, dirp
);
816 /* display the parameters */
817 printf(gettext("cfsadmin: list cache FS information\n"));
819 printf(gettext(" Version %3d\n"), clabel
.cl_cfsversion
);
821 printf(gettext(" maxblocks %3d%%\n"), uv
.uv_maxblocks
);
822 printf(gettext(" minblocks %3d%%\n"), uv
.uv_minblocks
);
823 printf(gettext(" threshblocks %3d%%\n"), uv
.uv_threshblocks
);
824 printf(gettext(" maxfiles %3d%%\n"), uv
.uv_maxfiles
);
825 printf(gettext(" minfiles %3d%%\n"), uv
.uv_minfiles
);
826 printf(gettext(" threshfiles %3d%%\n"), uv
.uv_threshfiles
);
827 printf(gettext(" maxfilesize %3dMB\n"), uv
.uv_maxfilesize
);
829 /* open the directory */
830 if ((dp
= opendir(dirp
)) == NULL
) {
831 pr_err(gettext("opendir %s failed: %s"), dirp
,
836 /* loop reading the contents of the directory */
838 while ((dep
= readdir64(dp
)) != NULL
) {
839 /* ignore . and .. */
840 if ((strcmp(dep
->d_name
, ".") == 0) ||
841 (strcmp(dep
->d_name
, "..") == 0))
845 sprintf(path
, "%s/%s", dirp
, dep
->d_name
);
846 xx
= lstat64(path
, &statinfo
);
848 pr_err(gettext("lstat %s failed: %s"),
849 path
, strerror(errno
));
854 /* ignore anything that is not a link */
855 if (!S_ISLNK(statinfo
.st_mode
))
858 /* print the file system cache directory name */
859 printf(gettext(" %s\n"), dep
->d_name
);
861 /* XXX anything else */
864 /* XXX what about stats */
875 * Grows the resource file in the specified directory
878 * dirp cache directory resource file is in
879 * oldcnt previous number of files in resource file
880 * newcnt new number of files in resource file
882 * Returns 0 for success, -1 for an error.
885 * precond(oldcnt <= newcnt)
886 * precond(cache is locked exclusively)
887 * precond(cache is not in use)
891 resource_file_grow(char *dirp
, int oldcnt
, int newcnt
)
894 char path
[CACHEFS_XMAXPATH
];
897 static struct cachefs_rinfo rold
, rnew
;
898 struct cache_usage cusage
, *cusagep
;
904 /* get info about the resouce file for the various sizes */
905 cachefs_resource_size(oldcnt
, &rold
);
906 cachefs_resource_size(newcnt
, &rnew
);
908 /* open the resource file for writing */
909 /* this file is < 2GB */
910 sprintf(path
, "%s/%s", dirp
, RESOURCE_NAME
);
911 fd
= open(path
, O_RDWR
);
913 pr_err(gettext("Could not open %s: %s, run fsck"), path
,
918 /* get info on the file */
919 xx
= fstat64(fd
, &st
);
921 pr_err(gettext("Could not stat %s: %s"), path
,
927 /* make sure the size is the correct */
928 if ((off_t
)st
.st_size
!= rold
.r_fsize
) {
929 pr_err(gettext("Resource file has wrong size %d %d, run fsck"),
930 (off_t
)st
.st_size
, rold
.r_fsize
);
935 /* read the cache usage structure */
936 xx
= read(fd
, &cusage
, sizeof (cusage
));
937 if (xx
!= sizeof (cusage
)) {
938 pr_err(gettext("Could not read cache_usage, %d, run fsck"),
945 xx
= lseek(fd
, 0, SEEK_SET
);
947 pr_err(gettext("Could not lseek %s: %s"), path
,
953 /* indicate cache is dirty if necessary */
955 if ((cusage
.cu_flags
& CUSAGE_ACTIVE
) == 0) {
957 cusage
.cu_flags
|= CUSAGE_ACTIVE
;
958 xx
= write(fd
, &cusage
, sizeof (cusage
));
959 if (xx
!= sizeof (cusage
)) {
961 "Could not write cache_usage, %d, run fsck"),
968 /* go to the end of the file */
969 xx
= lseek(fd
, 0, SEEK_END
);
971 pr_err(gettext("Could not lseek %s: %s"), path
,
977 /* grow the file to the new size */
978 memset(buf
, 0, sizeof (buf
));
979 cnt
= rnew
.r_fsize
- rold
.r_fsize
;
980 assert((cnt
% MAXBSIZE
) == 0);
983 xx
= write(fd
, buf
, sizeof (buf
));
984 if (xx
!= sizeof (buf
)) {
985 pr_err(gettext("Could not write file, %d, run fsck"),
992 /* mmap the file into our address space */
993 addrp
= mmap(NULL
, rnew
.r_fsize
, PROT_READ
| PROT_WRITE
, MAP_SHARED
,
995 if (addrp
== (void *)-1) {
996 pr_err(gettext("Could not mmap file %s: %s"), path
,
1002 /* close the file descriptor, we do not need it anymore */
1005 /* move the idents region to its new location */
1006 memmove(addrp
+ rnew
.r_identoffset
, addrp
+ rold
.r_identoffset
,
1009 /* zero out the old idents region that is now in the pointers region */
1010 memset(addrp
+ rold
.r_identoffset
, 0,
1011 rnew
.r_identoffset
- rold
.r_identoffset
);
1013 /* sync the data to the file */
1014 xx
= msync(addrp
, rnew
.r_fsize
, MS_SYNC
);
1016 pr_err(gettext("Could not sync file %s: %s"), path
,
1018 munmap(addrp
, rnew
.r_fsize
);
1022 /* mark the file as clean if it was not dirty originally */
1024 cusagep
= (struct cache_usage
*)addrp
;
1025 cusagep
->cu_flags
&= ~CUSAGE_ACTIVE
;
1027 /* sync the data to the file */
1028 xx
= msync(addrp
, rnew
.r_fsize
, MS_SYNC
);
1030 pr_err(gettext("Could not sync file %s: %s"), path
,
1032 munmap(addrp
, rnew
.r_fsize
);
1037 /* unmap the file */
1038 munmap(addrp
, rnew
.r_fsize
);
1040 /* return success */
1046 * resource_file_dirty
1049 * Marks the resource file as dirty.
1050 * This will cause fsck to fix it up the next time it
1053 * dirp cache directory resource file is in
1055 * Returns 0 for success, -1 for an error.
1058 * precond(cache is locked exclusively)
1059 * precond(cache is not in use)
1063 resource_file_dirty(char *dirp
)
1066 char path
[CACHEFS_XMAXPATH
];
1068 struct cache_usage cusage
;
1070 /* open the resource file for writing */
1071 /* this file is < 2GB */
1072 sprintf(path
, "%s/%s", dirp
, RESOURCE_NAME
);
1073 fd
= open(path
, O_RDWR
);
1075 pr_err(gettext("Could not open %s: %s, run fsck"), path
,
1080 /* read the cache usage structure */
1081 xx
= read(fd
, &cusage
, sizeof (cusage
));
1082 if (xx
!= sizeof (cusage
)) {
1083 pr_err(gettext("Could not read cache_usage, %d, run fsck"),
1090 xx
= lseek(fd
, 0, SEEK_SET
);
1092 pr_err(gettext("Could not lseek %s: %s"), path
,
1098 /* indicate cache is dirty if necessary */
1099 if ((cusage
.cu_flags
& CUSAGE_ACTIVE
) == 0) {
1100 cusage
.cu_flags
|= CUSAGE_ACTIVE
;
1101 xx
= write(fd
, &cusage
, sizeof (cusage
));
1102 if (xx
!= sizeof (cusage
)) {
1104 "Could not write cache_usage, %d, run fsck"),
1113 pr_err(gettext("Could not successfully close %s: %s"), path
,
1124 * Executes the _FIOCOD ioctl on the specified file.
1126 * name filename to issue ioctl on (or "all")
1128 * Returns 0 for success, -1 for an error.
1134 issue_cod(char *name
)
1141 struct mnttab mt
, mtpref
;
1143 #ifndef MNTTYPE_CACHEFS
1144 #define MNTTYPE_CACHEFS "cachefs"
1148 if (strcmp(name
, "all") == 0) {
1150 * if "all" was specified rather than a mount point,
1151 * we locate a cachefs mount in /etc/mnttab (any cachefs
1152 * mount will do). We issue the ioctl on this mount point,
1153 * and specify a non-zero argument to the ioctl. The non-zero
1154 * arg tells the kernel to do demandconst on all relevant
1157 if ((mfp
= fopen(MNTTAB
, "r")) == NULL
) {
1158 pr_err(gettext("Could not open %s."), MNTTAB
);
1161 mtpref
.mnt_special
= NULL
;
1162 mtpref
.mnt_mountp
= NULL
;
1163 mtpref
.mnt_mntopts
= NULL
;
1164 mtpref
.mnt_time
= NULL
;
1165 mtpref
.mnt_fstype
= MNTTYPE_CACHEFS
;
1166 if (getmntany(mfp
, &mt
, &mtpref
) != 0) {
1171 dirp
= mt
.mnt_mountp
;
1178 fd
= open(dirp
, O_RDONLY
);
1180 pr_err(gettext("Could not open %s, %s."),
1181 dirp
, strerror(errno
));
1185 /* issue the ioctl */
1186 xx
= ioctl(fd
, _FIOCOD
, arg
);
1188 if (errno
== ENOTTY
) {
1189 pr_err(gettext("%s is not a CacheFS file system"),
1191 } else if (errno
== EBUSY
) {
1193 /* we're quiet if "all" was specified */
1194 pr_err(gettext("CacheFS file system %s is not"
1195 " mounted demandconst."), dirp
);
1197 pr_err(gettext("Could not issue consistency request"
1198 " on %s\n %s."), dirp
, strerror(errno
));
1207 * simulate_disconnection
1210 * Sends the rpc message to the cachefsd to turn simulated
1211 * disconnection on or off
1213 * namep name of file system or "all"
1214 * disconnect 1 means disconnect, 0 means connect
1221 simulate_disconnection(char *namep
, int disconnect
)
1224 enum clnt_stat retval
;
1229 struct utsname info
;
1230 struct cachefsd_disconnection_args args
;
1232 struct timeval tval
;
1234 /* get the host name */
1237 pr_err(gettext("cannot get host name, errno %d"), errno
);
1240 hostp
= info
.nodename
;
1242 /* creat the connection to the daemon */
1243 clnt
= clnt_create(hostp
, CACHEFSDPROG
, CACHEFSDVERS
, "local");
1245 pr_err(gettext("cachefsd is not running"));
1249 /* give it a chance to complete */
1250 tval
.tv_sec
= 60 * 60 * 24;
1252 clnt_control(clnt
, CLSET_TIMEOUT
, (char *)&tval
);
1254 /* perform the operation */
1255 args
.cda_mntpt
= namep
;
1256 args
.cda_disconnect
= disconnect
;
1257 retval
= cachefsd_disconnection_1(&args
, &ret
, clnt
);
1258 if (retval
!= RPC_SUCCESS
) {
1259 clnt_perror(clnt
, gettext("cachefsd is not responding"));
1264 /* check for error from daemon */
1269 msgp
= "unknown error";
1272 msgp
= "not mounted disconnectable";
1275 msgp
= "already disconnected";
1278 msgp
= "not a cached file system";
1281 pr_err(gettext("Could not disconnect %s: %s"),
1286 msgp
= "unknown error";
1289 msgp
= "already connected";
1292 msgp
= "not simulated disconnection";
1295 msgp
= "not a cached file system";
1298 pr_err(gettext("Could not reconnect %s: %s"),