6253 F_GETLK doesn't always return lock owner
[illumos-gate.git] / usr / src / cmd / fs.d / cachefs / common / subr.c
blob887379c987b5f32cba614957dcef7682a871d9d3
1 /*
2 * CDDL HEADER START
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.
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]
20 * CDDL HEADER END
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * Common subroutines used by the programs in these subdirectories.
33 #include <locale.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <assert.h>
38 #include <unistd.h>
39 #include <limits.h>
40 #include <errno.h>
41 #include <wait.h>
42 #include <ctype.h>
43 #include <fcntl.h>
44 #include <ftw.h>
45 #include <dirent.h>
46 #include <sys/types.h>
47 #include <sys/time.h>
48 #include <utmpx.h>
49 #include <sys/uio.h>
50 #include <sys/param.h>
51 #include <sys/stat.h>
52 #include <sys/fcntl.h>
53 #include <sys/mount.h>
54 #include <sys/mntent.h>
55 #include <sys/mnttab.h>
56 #include <sys/mman.h>
57 #include <sys/fs/cachefs_fs.h>
58 #include "subr.h"
62 * cachefs_dir_lock
64 * Description:
65 * Gets a lock on the cache directory.
66 * To release the lock, call cachefs_dir_unlock
67 * with the returned value.
68 * Arguments:
69 * cachedirp name of the cache directory
70 * shared 1 if shared, 0 if not
71 * Returns:
72 * Returns -1 if the lock cannot be obtained immediatly.
73 * If the lock is obtained, returns a value >= 0.
74 * Preconditions:
75 * precond(cachedirp)
78 int
79 cachefs_dir_lock(const char *cachedirp, int shared)
81 int fd;
82 int xx;
83 int len;
84 char buf[MAXPATHLEN];
85 struct flock fl;
86 char *strp;
87 struct stat statb;
89 /* make a path prefix to the cache directory lock file */
90 strp = CACHEFS_ROOTRUN;
91 xx = stat(strp, &statb);
92 if ((xx < 0) || ((statb.st_mode & S_IFMT) != S_IFDIR))
93 strp = "/tmp";
95 /* won't overflow */
96 len = snprintf(buf, sizeof (buf), "%s/%s", strp, CACHEFS_LOCKDIR_PRE);
98 if (strlcat(buf, cachedirp, sizeof (buf)) >= sizeof (buf)) {
99 pr_err(gettext("Cache directory name %s is too long"),
100 cachedirp);
101 return (-1);
104 strp = &buf[len];
106 while (strp = strchr(strp, '/')) { /* convert path to a file */
107 *strp = '_';
111 * Create and open the cache directory lock file.
112 * This file will be <2G.
114 fd = open(buf, O_RDWR | O_CREAT, 0700);
115 if (fd == -1) {
116 pr_err(gettext("Cannot open lock file %s"), buf);
117 return (-1);
120 /* try to set the lock */
121 fl.l_type = (shared == 1) ? F_RDLCK : F_WRLCK;
122 fl.l_whence = 0;
123 fl.l_start = 1024;
124 fl.l_len = 1024;
125 fl.l_sysid = 0;
126 fl.l_pid = 0;
127 /* CACHEFS_LOCK_FILE will be <2GB */
128 xx = fcntl(fd, F_SETLKW, &fl);
129 if (xx == -1) {
130 if (errno == EAGAIN) {
131 pr_err(gettext("Cannot gain access to the "
132 "cache directory %s."), cachedirp);
133 } else {
134 pr_err(gettext("Unexpected failure on lock file %s %s"),
135 buf, strerror(errno));
137 close(fd);
138 return (-1);
141 /* return the file descriptor which can be used to release the lock */
142 return (fd);
147 * cachefs_dir_unlock
149 * Description:
150 * Releases an advisory lock on the cache directory.
151 * Arguments:
152 * fd cookie returned by cachefs_dir_lock
153 * Returns:
154 * Returns -1 if the lock cannot be released or 0 for success.
155 * Preconditions:
159 cachefs_dir_unlock(int fd)
161 struct flock fl;
162 int error = 0;
163 int xx;
165 /* release the lock */
166 fl.l_type = F_UNLCK;
167 fl.l_whence = 0;
168 fl.l_start = 1024;
169 fl.l_len = 1024;
170 fl.l_sysid = 0;
171 fl.l_pid = 0;
172 /* fd will be <2GB */
173 xx = fcntl(fd, F_SETLK, &fl);
174 if (xx == -1) {
175 pr_err(gettext("Unexpected failure releasing lock file %s"),
176 strerror(errno));
177 error = -1;
180 /* close the lock file */
181 close(fd);
183 return (error);
188 * cachefs_label_file_get
190 * Description:
191 * Gets the contents of a cache label file.
192 * Performs error checking on the file.
193 * Arguments:
194 * filep name of the cache label file
195 * clabelp where to put the file contents
196 * Returns:
197 * Returns 0 for success or -1 if an error occurs.
198 * Preconditions:
199 * precond(filep)
200 * precond(clabelp)
204 cachefs_label_file_get(const char *filep, struct cache_label *clabelp)
206 int xx;
207 int fd;
208 struct stat64 statinfo;
210 /* get info on the file */
211 xx = lstat64(filep, &statinfo);
212 if (xx == -1) {
213 if (errno != ENOENT) {
214 pr_err(gettext("Cannot stat file %s: %s"),
215 filep, strerror(errno));
216 } else {
217 pr_err(gettext("File %s does not exist."), filep);
220 return (-1);
223 /* if the file is the wrong type */
224 if (!S_ISREG(statinfo.st_mode)) {
225 pr_err(gettext("Cache label file %s corrupted"), filep);
226 return (-1);
229 /* if the file is the wrong size; it will be <2GB */
230 if (statinfo.st_size != (offset_t)sizeof (struct cache_label)) {
231 pr_err(gettext("Cache label file %s wrong size"), filep);
232 return (-1);
235 /* open the cache label file */
236 fd = open(filep, O_RDONLY);
237 if (fd == -1) {
238 pr_err(gettext("Error opening %s: %s"), filep,
239 strerror(errno));
240 return (-1);
243 /* read the current set of parameters */
244 xx = read(fd, clabelp, sizeof (struct cache_label));
245 if (xx != sizeof (struct cache_label)) {
246 pr_err(gettext("Reading %s failed: %s\n"), filep,
247 strerror(errno));
248 close(fd);
249 return (-1);
251 close(fd);
253 /* return success */
254 return (0);
259 * cachefs_label_file_put
261 * Description:
262 * Outputs the contents of a cache label object to a file.
263 * Arguments:
264 * filep name of the cache label file
265 * clabelp where to get the file contents
266 * Returns:
267 * Returns 0 for success or -1 if an error occurs.
268 * Preconditions:
269 * precond(filep)
270 * precond(clabelp)
274 cachefs_label_file_put(const char *filep, struct cache_label *clabelp)
276 int xx;
277 int fd;
279 /* get rid of the file if it already exists */
280 xx = unlink(filep);
281 if ((xx == -1) && (errno != ENOENT)) {
282 pr_err(gettext("Could not remove %s: %s"), filep,
283 strerror(errno));
284 return (-1);
287 /* open the cache label file; this file will be <2GB */
288 fd = open(filep, O_CREAT | O_RDWR, 0600);
289 if (fd == -1) {
290 pr_err(gettext("Error creating %s: %s"), filep,
291 strerror(errno));
292 return (-1);
295 /* write out the cache label object */
296 xx = write(fd, clabelp, sizeof (struct cache_label));
297 if (xx != sizeof (struct cache_label)) {
298 pr_err(gettext("Writing %s failed: %s"), filep,
299 strerror(errno));
300 close(fd);
301 return (-1);
304 /* make sure the contents get to disk */
305 if (fsync(fd) != 0) {
306 pr_err(gettext("Writing %s failed on sync: %s"), filep,
307 strerror(errno));
308 close(fd);
309 return (-1);
312 close(fd);
314 /* return success */
315 return (0);
319 cachefs_label_file_vcheck(char *filep, struct cache_label *clabelp)
321 /* check for an invalid version number */
322 if (clabelp->cl_cfsversion != CFSVERSION) {
323 pr_err(gettext("Cache label file %s corrupted"), filep);
324 return (-1);
327 return (0);
332 * cachefs_inuse
334 * Description:
335 * Tests whether or not the cache directory is in use by
336 * the cache file system.
337 * Arguments:
338 * cachedirp name of the file system cache directory
339 * Returns:
340 * Returns 1 if the cache is in use or an error, 0 if not.
341 * Preconditions:
342 * precond(cachedirp)
346 cachefs_inuse(const char *cachedirp)
348 int fd;
349 int xx;
350 char buf[MAXPATHLEN];
351 char *lockp = CACHEFS_LOCK_FILE;
352 struct flock fl;
354 /* see if path name is too long */
355 xx = strlen(cachedirp) + strlen(lockp) + 3;
356 if (xx >= MAXPATHLEN) {
357 pr_err(gettext("Cache directory name %s is too long"),
358 cachedirp);
359 return (1);
362 /* make a path to the cache directory lock file */
363 snprintf(buf, sizeof (buf), "%s/%s", cachedirp, lockp);
365 /* Open the kernel in use lock file. This file will be <2GB. */
366 fd = open(buf, O_RDWR, 0700);
367 if (fd == -1) {
368 pr_err(gettext("Cannot open lock file %s"), buf);
369 return (1);
372 /* test the lock status */
373 fl.l_type = F_WRLCK;
374 fl.l_whence = 0;
375 fl.l_start = 0;
376 fl.l_len = 1024;
377 fl.l_sysid = 0;
378 fl.l_pid = 0;
379 xx = fcntl(fd, F_GETLK, &fl);
380 if (xx == -1) {
381 pr_err(gettext("Unexpected failure on lock file %s %s"),
382 buf, strerror(errno));
383 close(fd);
384 return (1);
386 close(fd);
388 if (fl.l_type == F_UNLCK)
389 xx = 0;
390 else
391 xx = 1;
393 /* return whether or not the cache is in use */
394 return (xx);
399 * cachefs_resouce_size
401 * Description:
402 * Returns information about a resource file.
403 * Arguments:
404 * maxinodes number of inodes to be managed by the resource file
405 * rinfop set to info about the resource file
406 * Returns:
407 * Preconditions:
408 * precond(rinfop)
411 void
412 cachefs_resource_size(int maxinodes, struct cachefs_rinfo *rinfop)
414 int fsize;
416 fsize = MAXBSIZE;
418 rinfop->r_ptroffset = fsize;
420 fsize += MAXBSIZE * (maxinodes / CACHEFS_RLPMBS);
421 if ((maxinodes % CACHEFS_RLPMBS) != 0)
422 fsize += MAXBSIZE;
424 rinfop->r_fsize = fsize;
429 * cachefs_create_cache
431 * Description:
432 * Creates the specified cache directory and populates it as
433 * needed by CFS.
434 * Arguments:
435 * dirp the name of the cache directory
436 * uv user values (may be NULL)
437 * clabel label file contents, or placeholder for this
438 * Returns:
439 * Returns 0 for success or:
440 * -1 for an error
441 * -2 for an error and cache directory partially created
442 * Preconditions:
443 * precond(dirp)
447 cachefs_create_cache(char *dirp, struct cachefs_user_values *uv,
448 struct cache_label *clabel)
450 int xx;
451 char path[CACHEFS_XMAXPATH];
452 int fd;
453 void *bufp;
454 int cnt;
455 struct cache_usage cu;
456 FILE *fp;
457 char *parent;
458 struct statvfs64 svfs;
460 cu.cu_blksused = 0;
461 cu.cu_filesused = 0;
462 cu.cu_flags = 0;
464 /* make sure cache dir name is not too long */
465 if (strlen(dirp) > (size_t)PATH_MAX) {
466 pr_err(gettext("path name %s is too long."), dirp);
467 return (-1);
470 /* ensure the path isn't in cachefs */
471 parent = cachefs_file_to_dir(dirp);
472 if (parent == NULL) {
473 pr_err(gettext("Out of memory"));
474 return (-1);
476 if (statvfs64(parent, &svfs) != 0) {
477 pr_err(gettext("%s: %s"), parent, strerror(errno));
478 free(parent);
479 return (-1);
481 if (strcmp(svfs.f_basetype, CACHEFS_BASETYPE) == 0) {
482 pr_err(gettext("Cannot create cache in cachefs filesystem"));
483 free(parent);
484 return (-1);
486 free(parent);
488 /* make the directory */
489 if (mkdir(dirp, 0) == -1) {
490 switch (errno) {
491 case EEXIST:
492 pr_err(gettext("%s already exists."), dirp);
493 break;
495 default:
496 pr_err(gettext("mkdir %s failed: %s"),
497 dirp, strerror(errno));
499 return (-1);
501 cu.cu_filesused += 1;
502 cu.cu_blksused += 1;
504 /* convert user values to a cache_label */
505 if (uv != NULL) {
506 xx = cachefs_convert_uv2cl(uv, clabel, dirp);
507 if (xx)
508 return (-2);
512 * Create the cache directory lock file.
513 * Used by the kernel module to indicate the cache is in use.
514 * This file will be <2G.
516 snprintf(path, sizeof (path), "%s/%s", dirp, CACHEFS_LOCK_FILE);
517 fd = open(path, O_RDWR | O_CREAT, 0700);
518 if (fd == -1) {
519 pr_err(gettext("Cannot create lock file %s"), path);
520 return (-1);
522 close(fd);
524 /* make the directory for the back file system mount points */
525 /* note: we do not count this directory in the resources */
526 snprintf(path, sizeof (path), "%s/%s", dirp, BACKMNT_NAME);
527 if (mkdir(path, 0700) == -1) {
528 pr_err(gettext("mkdir %s failed: %s"), path,
529 strerror(errno));
530 return (-2);
533 /* make the directory for lost+found */
534 /* note: we do not count this directory in the resources */
535 snprintf(path, sizeof (path), "%s/%s", dirp, CACHEFS_LOSTFOUND_NAME);
536 if (mkdir(path, 0700) == -1) {
537 pr_err(gettext("mkdir %s failed: %s"), path,
538 strerror(errno));
539 return (-2);
542 /* make the networker "don't back up" file; this file is <2GB */
543 xx = 0;
544 snprintf(path, sizeof (path), "%s/%s", dirp, NOBACKUP_NAME);
545 if ((fp = fopen(path, "w")) != NULL) {
546 if (realpath(dirp, path) != NULL) {
547 fprintf(fp, "<< ./ >>\n");
548 fprintf(fp, "+skip: .?* *\n");
549 if (fclose(fp) == 0)
550 xx = 1;
553 if (xx == 0) {
554 snprintf(path, sizeof (path), "%s/%s", dirp, NOBACKUP_NAME);
555 pr_err(gettext("can't create %s"), path);
556 (void) unlink(path);
557 } else {
558 cu.cu_filesused += 1;
559 cu.cu_blksused += 1;
562 /* create the unmount file */
563 xx = 0;
564 snprintf(path, sizeof (path), "%s/%s", dirp, CACHEFS_UNMNT_FILE);
565 if ((fp = fopen(path, "w")) != NULL) {
566 time32_t btime;
568 btime = get_boottime();
569 fwrite((void *)&btime, sizeof (btime), 1, fp);
570 if (fclose(fp) == 0)
571 xx = 1;
573 if (xx == 0)
574 pr_err(gettext("can't create .cfs_unmnt file"));
576 /* create the cache label file */
577 snprintf(path, sizeof (path), "%s/%s", dirp, CACHELABEL_NAME);
578 xx = cachefs_label_file_put(path, clabel);
579 if (xx == -1) {
580 pr_err(gettext("creating %s failed."), path);
581 return (-2);
583 cu.cu_filesused += 1;
584 cu.cu_blksused += 1;
586 /* create the cache label duplicate file */
587 snprintf(path, sizeof (path), "%s/%s.dup", dirp, CACHELABEL_NAME);
588 xx = cachefs_label_file_put(path, clabel);
589 if (xx == -1) {
590 pr_err(gettext("creating %s failed."), path);
591 return (-2);
593 cu.cu_filesused += 1;
594 cu.cu_blksused += 1;
596 /* create the resouce file; this file will be <2GB */
597 snprintf(path, sizeof (path), "%s/%s", dirp, RESOURCE_NAME);
598 fd = open(path, O_CREAT | O_RDWR, 0600);
599 if (fd == -1) {
600 pr_err(gettext("create %s failed: %s"), path,
601 strerror(errno));
602 return (-2);
604 cu.cu_filesused += 1;
606 /* allocate a zeroed buffer for filling the resouce file */
607 bufp = calloc(1, MAXBSIZE);
608 if (bufp == NULL) {
609 pr_err(gettext("out of space %d."), MAXBSIZE);
610 close(fd);
611 return (-2);
614 /* determine number of MAXBSIZE chunks to make the file */
615 cnt = 1; /* for the header */
616 cnt += clabel->cl_maxinodes / CACHEFS_RLPMBS;
617 if ((clabel->cl_maxinodes % CACHEFS_RLPMBS) != 0)
618 ++cnt;
620 /* fill up the file with zeros */
621 for (xx = 0; xx < cnt; xx++) {
622 if (write(fd, bufp, MAXBSIZE) != MAXBSIZE) {
623 pr_err(gettext("write %s failed: %s"), path,
624 strerror(errno));
625 close(fd);
626 free(bufp);
627 return (-2);
630 free(bufp);
631 cu.cu_blksused += cnt;
633 /* position to the begining of the file */
634 if (lseek(fd, 0, SEEK_SET) == -1) {
635 pr_err(gettext("lseek %s failed: %s"), path,
636 strerror(errno));
637 close(fd);
638 return (-2);
641 /* write the cache usage structure */
642 xx = sizeof (struct cache_usage);
643 if (write(fd, &cu, xx) != xx) {
644 pr_err(gettext("cu write %s failed: %s"), path,
645 strerror(errno));
646 close(fd);
647 return (-2);
650 /* make sure the contents get to disk */
651 if (fsync(fd) != 0) {
652 pr_err(gettext("fsync %s failed: %s"), path,
653 strerror(errno));
654 close(fd);
655 return (-2);
657 close(fd);
659 /* return success */
660 return (0);
665 * cachefs_delete_all_cache
667 * Description:
668 * Delete all caches in cache directory.
669 * Arguments:
670 * dirp the pathname of of the cache directory to delete
671 * Returns:
672 * Returns 0 for success or -1 for an error.
673 * Preconditions:
674 * precond(dirp)
678 cachefs_delete_all_cache(char *dirp)
680 DIR *dp;
681 struct dirent64 *dep;
682 int xx;
683 char path[CACHEFS_XMAXPATH];
684 struct stat64 statinfo;
686 /* make sure cache dir name is not too long */
687 if (strlen(dirp) > (size_t)PATH_MAX) {
688 pr_err(gettext("path name %s is too long."),
689 dirp);
690 return (-1);
693 /* check that dirp is probably a cachefs directory */
694 snprintf(path, sizeof (path), "%s/%s", dirp, BACKMNT_NAME);
695 xx = access(path, R_OK | W_OK | X_OK);
697 snprintf(path, sizeof (path), "%s/%s", dirp, CACHELABEL_NAME);
698 xx |= access(path, R_OK | W_OK);
700 if (xx) {
701 pr_err(gettext("%s does not appear to be a "
702 "cachefs cache directory."), dirp);
703 return (-1);
706 /* remove the lost+found directory if it exists and is empty */
707 snprintf(path, sizeof (path), "%s/%s", dirp, CACHEFS_LOSTFOUND_NAME);
708 xx = rmdir(path);
709 if (xx == -1) {
710 if (errno == EEXIST) {
711 pr_err(gettext("Cannot delete cache '%s'. "
712 "First move files in '%s' to a safe location."),
713 dirp, path);
714 return (-1);
715 } else if (errno != ENOENT) {
716 pr_err(gettext("rmdir %s failed: %s"), path,
717 strerror(errno));
718 return (-1);
722 /* delete the back FS mount point directory if it exists */
723 snprintf(path, sizeof (path), "%s/%s", dirp, BACKMNT_NAME);
724 xx = lstat64(path, &statinfo);
725 if (xx == -1) {
726 if (errno != ENOENT) {
727 pr_err(gettext("lstat %s failed: %s"), path,
728 strerror(errno));
729 return (-1);
731 } else {
732 xx = nftw64(path, cachefs_delete_file, 16,
733 FTW_PHYS | FTW_DEPTH | FTW_MOUNT);
734 if (xx == -1) {
735 pr_err(gettext("unable to delete %s"), path);
736 return (-1);
740 /* open the cache directory specified */
741 if ((dp = opendir(dirp)) == NULL) {
742 pr_err(gettext("cannot open cache directory %s: %s"),
743 dirp, strerror(errno));
744 return (-1);
747 /* read the file names in the cache directory */
748 while ((dep = readdir64(dp)) != NULL) {
749 /* ignore . and .. */
750 if (strcmp(dep->d_name, ".") == 0 ||
751 strcmp(dep->d_name, "..") == 0)
752 continue;
754 /* stat the file */
755 snprintf(path, sizeof (path), "%s/%s", dirp, dep->d_name);
756 xx = lstat64(path, &statinfo);
757 if (xx == -1) {
758 if (errno == ENOENT) {
759 /* delete_cache may have nuked a directory */
760 continue;
763 pr_err(gettext("lstat %s failed: %s"),
764 path, strerror(errno));
765 closedir(dp);
766 return (-1);
769 /* ignore anything that is not a link */
770 if (!S_ISLNK(statinfo.st_mode))
771 continue;
773 /* delete the file system cache directory */
774 xx = cachefs_delete_cache(dirp, dep->d_name);
775 if (xx) {
776 closedir(dp);
777 return (-1);
780 closedir(dp);
782 /* remove the cache dir unmount file */
783 snprintf(path, sizeof (path), "%s/%s", dirp, CACHEFS_UNMNT_FILE);
784 xx = unlink(path);
785 if ((xx == -1) && (errno != ENOENT)) {
786 pr_err(gettext("unlink %s failed: %s"), path,
787 strerror(errno));
788 return (-1);
791 /* remove the cache label file */
792 snprintf(path, sizeof (path), "%s/%s", dirp, CACHELABEL_NAME);
793 xx = unlink(path);
794 if ((xx == -1) && (errno != ENOENT)) {
795 pr_err(gettext("unlink %s failed: %s"), path,
796 strerror(errno));
797 return (-1);
800 /* remove the cache label duplicate file */
801 snprintf(path, sizeof (path), "%s/%s.dup", dirp, CACHELABEL_NAME);
802 xx = unlink(path);
803 if ((xx == -1) && (errno != ENOENT)) {
804 pr_err(gettext("unlink %s failed: %s"), path,
805 strerror(errno));
806 return (-1);
809 /* remove the resource file */
810 snprintf(path, sizeof (path), "%s/%s", dirp, RESOURCE_NAME);
811 xx = unlink(path);
812 if ((xx == -1) && (errno != ENOENT)) {
813 pr_err(gettext("unlink %s failed: %s"), path,
814 strerror(errno));
815 return (-1);
818 /* remove the cachefslog file if it exists */
819 snprintf(path, sizeof (path), "%s/%s", dirp, LOG_STATUS_NAME);
820 (void) unlink(path);
822 /* remove the networker "don't back up" file if it exists */
823 snprintf(path, sizeof (path), "%s/%s", dirp, NOBACKUP_NAME);
824 (void) unlink(path);
826 /* remove the lock file */
827 snprintf(path, sizeof (path), "%s/%s", dirp, CACHEFS_LOCK_FILE);
828 xx = unlink(path);
829 if ((xx == -1) && (errno != ENOENT)) {
830 pr_err(gettext("unlink %s failed: %s"), path,
831 strerror(errno));
832 return (-1);
835 /* remove the directory */
836 xx = rmdir(dirp);
837 if (xx == -1) {
838 pr_err(gettext("rmdir %s failed: %s"), dirp,
839 strerror(errno));
840 return (-1);
843 /* return success */
844 return (0);
849 * cachefs_delete_cache
851 * Description:
852 * Deletes the specified file system cache.
853 * Arguments:
854 * dirp cache directory name
855 * namep file system cache directory to delete
856 * Returns:
857 * Returns 0 for success, -1 for failure.
858 * Preconditions:
859 * precond(dirp)
860 * precond(namep)
864 cachefs_delete_cache(char *dirp, char *namep)
866 char path[CACHEFS_XMAXPATH];
867 char buf[CACHEFS_XMAXPATH];
868 int xx;
869 struct stat64 statinfo;
871 /* make sure cache dir name is not too long */
872 if (strlen(dirp) > (size_t)PATH_MAX) {
873 pr_err(gettext("path name %s is too long."),
874 dirp);
875 return (-1);
878 /* construct the path name of the file system cache directory */
879 snprintf(path, sizeof (path), "%s/%s", dirp, namep);
881 /* stat the specified file */
882 xx = lstat64(path, &statinfo);
883 if (xx == -1) {
884 pr_err(gettext("lstat %s failed: %s"), path,
885 strerror(errno));
886 return (-1);
889 /* make sure name is a symbolic link */
890 if (!S_ISLNK(statinfo.st_mode)) {
891 pr_err(gettext("\"%s\" is not a valid cache id."), namep);
892 return (-1);
895 /* read the contents of the symbolic link */
896 xx = readlink(path, buf, sizeof (buf));
897 if (xx == -1) {
898 pr_err(gettext("Readlink of %s failed: %s"), path,
899 strerror(errno));
900 return (-1);
902 buf[xx] = '\0';
904 /* remove the directory */
905 snprintf(path, sizeof (path), "%s/%s", dirp, buf);
906 xx = nftw64(path, cachefs_delete_file, 16,
907 FTW_PHYS | FTW_DEPTH | FTW_MOUNT);
908 if (xx == -1) {
909 pr_err(gettext("directory walk of %s failed."), dirp);
910 return (-1);
913 /* delete the link */
914 snprintf(path, sizeof (path), "%s/%s", dirp, namep);
915 if (unlink(path) == -1) {
916 pr_err(gettext("unlink %s failed: %s"), path,
917 strerror(errno));
918 return (-1);
921 /* return success */
922 return (0);
927 * cachefs_delete_file
929 * Description:
930 * Remove a file or directory; called by nftw64().
931 * Arguments:
932 * namep pathname of the file
933 * statp stat info about the file
934 * flg info about file
935 * ftwp depth information
936 * Returns:
937 * Returns 0 for success, -1 for failure.
938 * Preconditions:
939 * precond(namep)
943 cachefs_delete_file(const char *namep, const struct stat64 *statp, int flg,
944 struct FTW *ftwp)
946 /* ignore . and .. */
947 if (strcmp(namep, ".") == 0 || strcmp(namep, "..") == 0)
948 return (0);
950 switch (flg) {
951 case FTW_F: /* files */
952 case FTW_SL:
953 if (unlink(namep) == -1) {
954 pr_err(gettext("unlink %s failed: %s"),
955 namep, strerror(errno));
956 return (-1);
958 break;
960 case FTW_DP: /* directories that have their children processed */
961 if (rmdir(namep) == -1) {
962 pr_err(gettext("rmdir %s failed: %s"),
963 namep, strerror(errno));
964 return (-1);
966 break;
968 case FTW_D: /* ignore directories if children not processed */
969 break;
971 default:
972 pr_err(gettext("failure on file %s, flg %d."),
973 namep, flg);
974 return (-1);
977 /* return success */
978 return (0);
983 * cachefs_convert_uv2cl
985 * Description:
986 * Copies the contents of a cachefs_user_values object into a
987 * cache_label object, performing the necessary conversions.
988 * Arguments:
989 * uvp cachefs_user_values to copy from
990 * clp cache_label to copy into
991 * dirp cache directory
992 * Returns:
993 * Returns 0 for success, -1 for an error.
994 * Preconditions:
995 * precond(uvp)
996 * precond(clp)
997 * precond(dirp)
1001 cachefs_convert_uv2cl(const struct cachefs_user_values *uvp,
1002 struct cache_label *clp, const char *dirp)
1004 struct statvfs64 fs;
1005 int xx;
1006 double ftmp;
1007 double temp;
1009 /* get file system information */
1010 xx = statvfs64(dirp, &fs);
1011 if (xx == -1) {
1012 pr_err(gettext("statvfs %s failed: %s"), dirp,
1013 strerror(errno));
1014 return (-1);
1017 ftmp = (double)fs.f_frsize / (double)MAXBSIZE;
1019 /* front fs is less than 1 terabyte */
1020 temp = (double)uvp->uv_maxblocks / 100.0 *
1021 (double)fs.f_blocks * ftmp + .5;
1022 clp->cl_maxblks = temp < (double)INT_MAX ? (int)temp : INT_MAX;
1024 temp = (double)uvp->uv_minblocks / 100.0 *
1025 (double)fs.f_blocks * ftmp + .5;
1026 clp->cl_blockmin = temp < (double)INT_MAX ? (int)temp : INT_MAX;
1028 temp = (double)uvp->uv_threshblocks / 100.0 *
1029 (double)fs.f_blocks * ftmp + .5;
1030 clp->cl_blocktresh = temp < (double)INT_MAX ? (int)temp : INT_MAX;
1032 temp = (double)uvp->uv_maxfiles / 100.0 * (double)fs.f_files + .5;
1033 clp->cl_maxinodes = temp < (double)INT_MAX ? (int)temp : INT_MAX;
1035 temp = (double)uvp->uv_minfiles / 100.0 * (double)fs.f_files + .5;
1036 clp->cl_filemin = temp < (double)INT_MAX ? (int)temp : INT_MAX;
1038 temp = (double)uvp->uv_threshfiles / 100.0 * (double)fs.f_files +.5;
1039 clp->cl_filetresh = temp < (double)INT_MAX ? (int)temp : INT_MAX;
1041 ftmp = (double)(1024 * 1024) / (double)MAXBSIZE;
1042 clp->cl_maxfiles = uvp->uv_maxfilesize * ftmp + .5;
1044 clp->cl_blkhiwat = uvp->uv_hiblocks / 100.0 * clp->cl_maxblks + .5;
1045 clp->cl_blklowat = uvp->uv_lowblocks / 100.0 * clp->cl_maxblks + .5;
1047 clp->cl_filehiwat = uvp->uv_hifiles / 100.0 * clp->cl_maxinodes + .5;
1048 clp->cl_filelowat = uvp->uv_lowfiles / 100.0 * clp->cl_maxinodes + .5;
1050 clp->cl_cfsversion = CFSVERSION;
1052 /* return success */
1053 return (0);
1058 * cachefs_convert_cl2uv
1060 * Description:
1061 * Copies the contents of a cache_label object into a
1062 * cachefs_user_values object, performing the necessary conversions.
1063 * Arguments:
1064 * clp cache_label to copy from
1065 * uvp cachefs_user_values to copy into
1066 * dirp cache directory
1067 * Returns:
1068 * Returns 0 for success, -1 for an error.
1069 * Preconditions:
1070 * precond(clp)
1071 * precond(uvp)
1072 * precond(dirp)
1076 cachefs_convert_cl2uv(const struct cache_label *clp,
1077 struct cachefs_user_values *uvp, const char *dirp)
1079 struct statvfs64 fs;
1080 int xx;
1081 double temp;
1082 double ftmp;
1083 long long ltmp;
1085 /* get file system information */
1086 xx = statvfs64(dirp, &fs);
1087 if (xx == -1) {
1088 pr_err(gettext("statvfs %s failed: %s"), dirp,
1089 strerror(errno));
1090 return (-1);
1093 #define BOUND(yy) \
1094 yy = (yy < 0) ? 0 : yy; \
1095 yy = (yy > 100) ? 100 : yy;
1097 ftmp = (double)MAXBSIZE / (double)fs.f_frsize;
1099 temp = (double)clp->cl_maxblks * ftmp /
1100 (double)fs.f_blocks * 100. + .5;
1101 BOUND(temp);
1102 uvp->uv_maxblocks = (int)temp;
1104 temp = (double)clp->cl_blockmin * ftmp /
1105 (double)fs.f_blocks * 100. + .5;
1106 BOUND(temp);
1107 uvp->uv_minblocks = (int)temp;
1109 temp = (double)clp->cl_blocktresh * ftmp /
1110 (double)fs.f_blocks * 100. + .5;
1111 BOUND(temp);
1112 uvp->uv_threshblocks = (int)temp;
1114 temp = ((double)clp->cl_maxinodes / fs.f_files) * 100. + .5;
1115 BOUND(temp);
1116 uvp->uv_maxfiles = (int)temp;
1118 temp = ((double)clp->cl_filemin / fs.f_files) * 100. + .5;
1119 BOUND(temp);
1120 uvp->uv_minfiles = (int)temp;
1122 temp = ((double)clp->cl_filetresh / fs.f_files) * 100. + .5;
1123 BOUND(temp);
1124 uvp->uv_threshfiles = (int)temp;
1126 ltmp = ((long long)clp->cl_maxfiles * MAXBSIZE);
1127 uvp->uv_maxfilesize = (ltmp + (MAXBSIZE / 2)) / (1024 * 1024);
1129 xx = ((double)clp->cl_blkhiwat / clp->cl_maxblks) * 100. + .5;
1130 BOUND(xx);
1131 uvp->uv_hiblocks = xx;
1133 xx = ((double)clp->cl_blklowat / clp->cl_maxblks) * 100. + .5;
1134 BOUND(xx);
1135 uvp->uv_lowblocks = xx;
1137 xx = ((double)clp->cl_filehiwat / clp->cl_maxinodes) * 100. + .5;
1138 BOUND(xx);
1139 uvp->uv_hifiles = xx;
1141 xx = ((double)clp->cl_filelowat / clp->cl_maxinodes) * 100. + .5;
1142 BOUND(xx);
1143 uvp->uv_lowfiles = xx;
1145 /* return success */
1146 return (0);
1150 * cachefs_file_to_dir
1152 * takes in a path, and returns the parent directory of that path.
1154 * it's the caller's responsibility to free the pointer returned by
1155 * this function.
1158 char *
1159 cachefs_file_to_dir(const char *path)
1161 char *rc, *cp;
1163 if (path == NULL)
1164 return (NULL);
1166 rc = strdup(path);
1167 if (rc == NULL)
1168 return (NULL);
1170 if ((cp = strrchr(rc, '/')) == NULL) {
1173 * if no slashes at all, return "." (current directory).
1176 (void) free(rc);
1177 rc = strdup(".");
1179 } else if (cp == rc) {
1182 * else, if the last '/' is the first character, chop
1183 * off from there (i.e. return "/").
1186 rc[1] = '\0';
1188 } else {
1191 * else, we have a path like /foo/bar or foo/bar.
1192 * chop off from the last '/'.
1195 *cp = '\0';
1199 return (rc);
1203 * cachefs_clean_flag_test
1205 * Description:
1206 * Tests whether or not the clean flag on the file system
1207 * is set.
1208 * Arguments:
1209 * cachedirp name of the the file system cache directory
1210 * Returns:
1211 * Returns 1 if the cache was shut down cleanly, 0 if not.
1212 * Preconditions:
1213 * precond(cachedirp)
1217 cachefs_clean_flag_test(const char *cachedirp)
1219 char *namep;
1220 int xx;
1221 char buf[MAXPATHLEN];
1222 int fd;
1223 struct cache_usage cu;
1225 /* construct the path name of the resource file */
1226 namep = RESOURCE_NAME;
1227 xx = strlen(cachedirp) + strlen(namep) + 3;
1228 if (xx >= MAXPATHLEN) {
1229 pr_err(gettext("Path name too long %s/%s"),
1230 cachedirp, namep);
1231 return (39);
1233 snprintf(buf, sizeof (buf), "%s/%s", cachedirp, namep);
1235 /* open the file; it will be <2GB */
1236 fd = open(buf, O_RDONLY);
1237 if (fd == -1) {
1238 pr_err(gettext("Cannot open %s: %s"), buf, strerror(errno));
1239 return (0);
1242 /* read the cache_usage structure */
1243 xx = read(fd, &cu, sizeof (cu));
1244 if (xx != sizeof (cu)) {
1245 pr_err(gettext("Error reading %s: %d %s"), buf,
1246 xx, strerror(errno));
1247 close(fd);
1248 return (0);
1250 close(fd);
1252 /* return state of the cache */
1253 return ((cu.cu_flags & CUSAGE_ACTIVE) == 0);
1256 time32_t
1257 get_boottime()
1259 struct utmpx id, *putmp;
1261 id.ut_type = BOOT_TIME;
1262 setutxent();
1263 if ((putmp = getutxid(&id)) != NULL)
1264 return ((time32_t)putmp->ut_tv.tv_sec);
1265 return (-1);