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 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Common subroutines used by the programs in these subdirectories. 31 */ 32 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" 59 60 /* 61 * 62 * cachefs_dir_lock 63 * 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) 76 */ 77 78 int 79 cachefs_dir_lock(const char *cachedirp, int shared) 80 { 81 int fd; 82 int xx; 83 int len; 84 char buf[MAXPATHLEN]; 85 struct flock fl; 86 char *strp; 87 struct stat statb; 88 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"; 94 95 /* won't overflow */ 96 len = snprintf(buf, sizeof (buf), "%s/%s", strp, CACHEFS_LOCKDIR_PRE); 97 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); 102 } 103 104 strp = &buf[len]; 105 106 while (strp = strchr(strp, '/')) { /* convert path to a file */ 107 *strp = '_'; 108 } 109 110 /* 111 * Create and open the cache directory lock file. 112 * This file will be <2G. 113 */ 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); 118 } 119 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)); 136 } 137 close(fd); 138 return (-1); 139 } 140 141 /* return the file descriptor which can be used to release the lock */ 142 return (fd); 143 } 144 145 /* 146 * 147 * cachefs_dir_unlock 148 * 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: 156 */ 157 158 int 159 cachefs_dir_unlock(int fd) 160 { 161 struct flock fl; 162 int error = 0; 163 int xx; 164 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; 178 } 179 180 /* close the lock file */ 181 close(fd); 182 183 return (error); 184 } 185 186 /* 187 * 188 * cachefs_label_file_get 189 * 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) 201 */ 202 203 int 204 cachefs_label_file_get(const char *filep, struct cache_label *clabelp) 205 { 206 int xx; 207 int fd; 208 struct stat64 statinfo; 209 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); 218 } 219 220 return (-1); 221 } 222 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); 227 } 228 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); 233 } 234 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); 241 } 242 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); 250 } 251 close(fd); 252 253 /* return success */ 254 return (0); 255 } 256 257 /* 258 * 259 * cachefs_label_file_put 260 * 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) 271 */ 272 273 int 274 cachefs_label_file_put(const char *filep, struct cache_label *clabelp) 275 { 276 int xx; 277 int fd; 278 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); 285 } 286 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); 293 } 294 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); 302 } 303 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); 310 } 311 312 close(fd); 313 314 /* return success */ 315 return (0); 316 } 317 318 int 319 cachefs_label_file_vcheck(char *filep, struct cache_label *clabelp) 320 { 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); 325 } 326 327 return (0); 328 } 329 330 /* 331 * 332 * cachefs_inuse 333 * 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) 343 */ 344 345 int 346 cachefs_inuse(const char *cachedirp) 347 { 348 int fd; 349 int xx; 350 char buf[MAXPATHLEN]; 351 char *lockp = CACHEFS_LOCK_FILE; 352 struct flock fl; 353 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); 360 } 361 362 /* make a path to the cache directory lock file */ 363 snprintf(buf, sizeof (buf), "%s/%s", cachedirp, lockp); 364 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); 370 } 371 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); 385 } 386 close(fd); 387 388 if (fl.l_type == F_UNLCK) 389 xx = 0; 390 else 391 xx = 1; 392 393 /* return whether or not the cache is in use */ 394 return (xx); 395 } 396 397 /* 398 * 399 * cachefs_resouce_size 400 * 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) 409 */ 410 411 void 412 cachefs_resource_size(int maxinodes, struct cachefs_rinfo *rinfop) 413 { 414 int fsize; 415 416 fsize = MAXBSIZE; 417 418 rinfop->r_ptroffset = fsize; 419 420 fsize += MAXBSIZE * (maxinodes / CACHEFS_RLPMBS); 421 if ((maxinodes % CACHEFS_RLPMBS) != 0) 422 fsize += MAXBSIZE; 423 424 rinfop->r_fsize = fsize; 425 } 426 427 /* 428 * 429 * cachefs_create_cache 430 * 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) 444 */ 445 446 int 447 cachefs_create_cache(char *dirp, struct cachefs_user_values *uv, 448 struct cache_label *clabel) 449 { 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; 459 460 cu.cu_blksused = 0; 461 cu.cu_filesused = 0; 462 cu.cu_flags = 0; 463 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); 468 } 469 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); 475 } 476 if (statvfs64(parent, &svfs) != 0) { 477 pr_err(gettext("%s: %s"), parent, strerror(errno)); 478 free(parent); 479 return (-1); 480 } 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); 485 } 486 free(parent); 487 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; 494 495 default: 496 pr_err(gettext("mkdir %s failed: %s"), 497 dirp, strerror(errno)); 498 } 499 return (-1); 500 } 501 cu.cu_filesused += 1; 502 cu.cu_blksused += 1; 503 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); 509 } 510 511 /* 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. 515 */ 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); 521 } 522 close(fd); 523 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); 531 } 532 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); 540 } 541 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; 551 } 552 } 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; 560 } 561 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; 567 568 btime = get_boottime(); 569 fwrite((void *)&btime, sizeof (btime), 1, fp); 570 if (fclose(fp) == 0) 571 xx = 1; 572 } 573 if (xx == 0) 574 pr_err(gettext("can't create .cfs_unmnt file")); 575 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); 582 } 583 cu.cu_filesused += 1; 584 cu.cu_blksused += 1; 585 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); 592 } 593 cu.cu_filesused += 1; 594 cu.cu_blksused += 1; 595 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); 603 } 604 cu.cu_filesused += 1; 605 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); 612 } 613 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; 619 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); 628 } 629 } 630 free(bufp); 631 cu.cu_blksused += cnt; 632 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); 639 } 640 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); 648 } 649 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); 656 } 657 close(fd); 658 659 /* return success */ 660 return (0); 661 } 662 663 /* 664 * 665 * cachefs_delete_all_cache 666 * 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) 675 */ 676 677 int 678 cachefs_delete_all_cache(char *dirp) 679 { 680 DIR *dp; 681 struct dirent64 *dep; 682 int xx; 683 char path[CACHEFS_XMAXPATH]; 684 struct stat64 statinfo; 685 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); 691 } 692 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); 696 697 snprintf(path, sizeof (path), "%s/%s", dirp, CACHELABEL_NAME); 698 xx |= access(path, R_OK | W_OK); 699 700 if (xx) { 701 pr_err(gettext("%s does not appear to be a " 702 "cachefs cache directory."), dirp); 703 return (-1); 704 } 705 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); 719 } 720 } 721 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); 730 } 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); 737 } 738 } 739 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); 745 } 746 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; 753 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; 761 } 762 763 pr_err(gettext("lstat %s failed: %s"), 764 path, strerror(errno)); 765 closedir(dp); 766 return (-1); 767 } 768 769 /* ignore anything that is not a link */ 770 if (!S_ISLNK(statinfo.st_mode)) 771 continue; 772 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); 778 } 779 } 780 closedir(dp); 781 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); 789 } 790 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); 798 } 799 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); 807 } 808 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); 816 } 817 818 /* remove the cachefslog file if it exists */ 819 snprintf(path, sizeof (path), "%s/%s", dirp, LOG_STATUS_NAME); 820 (void) unlink(path); 821 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); 825 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); 833 } 834 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); 841 } 842 843 /* return success */ 844 return (0); 845 } 846 847 /* 848 * 849 * cachefs_delete_cache 850 * 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) 861 */ 862 863 int 864 cachefs_delete_cache(char *dirp, char *namep) 865 { 866 char path[CACHEFS_XMAXPATH]; 867 char buf[CACHEFS_XMAXPATH]; 868 int xx; 869 struct stat64 statinfo; 870 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); 876 } 877 878 /* construct the path name of the file system cache directory */ 879 snprintf(path, sizeof (path), "%s/%s", dirp, namep); 880 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); 887 } 888 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); 893 } 894 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); 901 } 902 buf[xx] = '\0'; 903 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); 911 } 912 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); 919 } 920 921 /* return success */ 922 return (0); 923 } 924 925 /* 926 * 927 * cachefs_delete_file 928 * 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) 940 */ 941 942 int 943 cachefs_delete_file(const char *namep, const struct stat64 *statp, int flg, 944 struct FTW *ftwp) 945 { 946 /* ignore . and .. */ 947 if (strcmp(namep, ".") == 0 || strcmp(namep, "..") == 0) 948 return (0); 949 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); 957 } 958 break; 959 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); 965 } 966 break; 967 968 case FTW_D: /* ignore directories if children not processed */ 969 break; 970 971 default: 972 pr_err(gettext("failure on file %s, flg %d."), 973 namep, flg); 974 return (-1); 975 } 976 977 /* return success */ 978 return (0); 979 } 980 981 /* 982 * 983 * cachefs_convert_uv2cl 984 * 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) 998 */ 999 1000 int 1001 cachefs_convert_uv2cl(const struct cachefs_user_values *uvp, 1002 struct cache_label *clp, const char *dirp) 1003 { 1004 struct statvfs64 fs; 1005 int xx; 1006 double ftmp; 1007 double temp; 1008 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); 1015 } 1016 1017 ftmp = (double)fs.f_frsize / (double)MAXBSIZE; 1018 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; 1023 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; 1027 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; 1031 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; 1034 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; 1037 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; 1040 1041 ftmp = (double)(1024 * 1024) / (double)MAXBSIZE; 1042 clp->cl_maxfiles = uvp->uv_maxfilesize * ftmp + .5; 1043 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; 1046 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; 1049 1050 clp->cl_cfsversion = CFSVERSION; 1051 1052 /* return success */ 1053 return (0); 1054 } 1055 1056 /* 1057 * 1058 * cachefs_convert_cl2uv 1059 * 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) 1073 */ 1074 1075 int 1076 cachefs_convert_cl2uv(const struct cache_label *clp, 1077 struct cachefs_user_values *uvp, const char *dirp) 1078 { 1079 struct statvfs64 fs; 1080 int xx; 1081 double temp; 1082 double ftmp; 1083 long long ltmp; 1084 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); 1091 } 1092 1093 #define BOUND(yy) \ 1094 yy = (yy < 0) ? 0 : yy; \ 1095 yy = (yy > 100) ? 100 : yy; 1096 1097 ftmp = (double)MAXBSIZE / (double)fs.f_frsize; 1098 1099 temp = (double)clp->cl_maxblks * ftmp / 1100 (double)fs.f_blocks * 100. + .5; 1101 BOUND(temp); 1102 uvp->uv_maxblocks = (int)temp; 1103 1104 temp = (double)clp->cl_blockmin * ftmp / 1105 (double)fs.f_blocks * 100. + .5; 1106 BOUND(temp); 1107 uvp->uv_minblocks = (int)temp; 1108 1109 temp = (double)clp->cl_blocktresh * ftmp / 1110 (double)fs.f_blocks * 100. + .5; 1111 BOUND(temp); 1112 uvp->uv_threshblocks = (int)temp; 1113 1114 temp = ((double)clp->cl_maxinodes / fs.f_files) * 100. + .5; 1115 BOUND(temp); 1116 uvp->uv_maxfiles = (int)temp; 1117 1118 temp = ((double)clp->cl_filemin / fs.f_files) * 100. + .5; 1119 BOUND(temp); 1120 uvp->uv_minfiles = (int)temp; 1121 1122 temp = ((double)clp->cl_filetresh / fs.f_files) * 100. + .5; 1123 BOUND(temp); 1124 uvp->uv_threshfiles = (int)temp; 1125 1126 ltmp = ((long long)clp->cl_maxfiles * MAXBSIZE); 1127 uvp->uv_maxfilesize = (ltmp + (MAXBSIZE / 2)) / (1024 * 1024); 1128 1129 xx = ((double)clp->cl_blkhiwat / clp->cl_maxblks) * 100. + .5; 1130 BOUND(xx); 1131 uvp->uv_hiblocks = xx; 1132 1133 xx = ((double)clp->cl_blklowat / clp->cl_maxblks) * 100. + .5; 1134 BOUND(xx); 1135 uvp->uv_lowblocks = xx; 1136 1137 xx = ((double)clp->cl_filehiwat / clp->cl_maxinodes) * 100. + .5; 1138 BOUND(xx); 1139 uvp->uv_hifiles = xx; 1140 1141 xx = ((double)clp->cl_filelowat / clp->cl_maxinodes) * 100. + .5; 1142 BOUND(xx); 1143 uvp->uv_lowfiles = xx; 1144 1145 /* return success */ 1146 return (0); 1147 } 1148 1149 /* 1150 * cachefs_file_to_dir 1151 * 1152 * takes in a path, and returns the parent directory of that path. 1153 * 1154 * it's the caller's responsibility to free the pointer returned by 1155 * this function. 1156 */ 1157 1158 char * 1159 cachefs_file_to_dir(const char *path) 1160 { 1161 char *rc, *cp; 1162 1163 if (path == NULL) 1164 return (NULL); 1165 1166 rc = strdup(path); 1167 if (rc == NULL) 1168 return (NULL); 1169 1170 if ((cp = strrchr(rc, '/')) == NULL) { 1171 1172 /* 1173 * if no slashes at all, return "." (current directory). 1174 */ 1175 1176 (void) free(rc); 1177 rc = strdup("."); 1178 1179 } else if (cp == rc) { 1180 1181 /* 1182 * else, if the last '/' is the first character, chop 1183 * off from there (i.e. return "/"). 1184 */ 1185 1186 rc[1] = '\0'; 1187 1188 } else { 1189 1190 /* 1191 * else, we have a path like /foo/bar or foo/bar. 1192 * chop off from the last '/'. 1193 */ 1194 1195 *cp = '\0'; 1196 1197 } 1198 1199 return (rc); 1200 } 1201 1202 /* 1203 * cachefs_clean_flag_test 1204 * 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) 1214 */ 1215 1216 int 1217 cachefs_clean_flag_test(const char *cachedirp) 1218 { 1219 char *namep; 1220 int xx; 1221 char buf[MAXPATHLEN]; 1222 int fd; 1223 struct cache_usage cu; 1224 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); 1232 } 1233 snprintf(buf, sizeof (buf), "%s/%s", cachedirp, namep); 1234 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); 1240 } 1241 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); 1249 } 1250 close(fd); 1251 1252 /* return state of the cache */ 1253 return ((cu.cu_flags & CUSAGE_ACTIVE) == 0); 1254 } 1255 1256 time32_t 1257 get_boottime() 1258 { 1259 struct utmpx id, *putmp; 1260 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); 1266 }