1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Various support routines. 31 */ 32 33 #include <libintl.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <errno.h> 38 #include <dirent.h> 39 #include <wait.h> 40 #include <stdarg.h> 41 #include <limits.h> 42 #include <rpc/rpc.h> 43 #include <rpc/pmap_clnt.h> /* for pmap_unset */ 44 #include <string.h> /* strcmp */ 45 #include <signal.h> 46 #include <unistd.h> /* setsid */ 47 #include <sys/utsname.h> 48 #include <sys/param.h> 49 #include <sys/mnttab.h> 50 #include <sys/vfstab.h> 51 #include <sys/types.h> 52 #include <sys/stat.h> 53 #include <memory.h> 54 #include <stropts.h> 55 #include <netconfig.h> 56 #include <sys/resource.h> /* rlimit */ 57 #include <thread.h> 58 #include <synch.h> 59 #include <mdbug/mdbug.h> 60 #include <sys/fs/cachefs_fs.h> 61 #include <sys/fs/cachefs_dlog.h> 62 #include <sys/fs/cachefs_ioctl.h> 63 #include "cfsd.h" 64 #include "cfsd_kmod.h" 65 #include "cfsd_maptbl.h" 66 #include "cfsd_logfile.h" 67 #include "cfsd_fscache.h" 68 #include "cfsd_cache.h" 69 #include "cfsd_all.h" 70 #include <common/cachefsd.h> 71 #include <common/subr.h> 72 73 /* forward references */ 74 void *subr_mount_thread(void *datap); 75 int subr_fsck_cache(const char *cachedirp); 76 void subr_doexec(const char *fstype, char *newargv[], const char *progp); 77 78 /* 79 * subr_add_mount 80 * 81 * Description: 82 * Adds the specified file system to the data structures. 83 * Arguments: 84 * allp ptr to set of data structures 85 * dirp ptr to name of cache directory 86 * idp ptr to id of file system cache in dirp 87 * Returns: 88 * Preconditions: 89 * precond(allp) 90 * precond(dirp) 91 * precond(idp) 92 */ 93 void 94 subr_add_mount(cfsd_all_object_t *all_object_p, 95 const char *dirp, 96 const char *idp) 97 { 98 int xx; 99 thread_t new_thread; 100 cfsd_cache_object_t *cache_object_p; 101 cfsd_fscache_object_t *fscache_object_p; 102 103 dbug_enter("subr_add_mount"); 104 105 dbug_precond(all_object_p); 106 dbug_precond(dirp); 107 dbug_precond(idp); 108 109 dbug_print(("info", "cachedir %s, cacheid %s", dirp, idp)); 110 111 /* find or create the cache object */ 112 all_lock(all_object_p); 113 cache_object_p = all_cachelist_find(all_object_p, dirp); 114 if (cache_object_p == NULL) { 115 /* make the cache object */ 116 cache_object_p = cfsd_cache_create(); 117 xx = all_object_p->i_nextcacheid; 118 xx = cache_setup(cache_object_p, dirp, xx); 119 if (xx == 0) { 120 dbug_print(("error", "invalid cache %s", dirp)); 121 cfsd_cache_destroy(cache_object_p); 122 all_unlock(all_object_p); 123 dbug_leave("subr_add_mount"); 124 return; 125 } 126 all_cachelist_add(all_object_p, cache_object_p); 127 all_cachefstab_update(all_object_p); 128 } 129 cache_lock(cache_object_p); 130 cache_object_p->i_refcnt++; 131 cache_unlock(cache_object_p); 132 all_unlock(all_object_p); 133 134 /* find or create the fscache object */ 135 cache_lock(cache_object_p); 136 fscache_object_p = cache_fscachelist_find(cache_object_p, idp); 137 if (fscache_object_p == NULL) { 138 /* make the fscache object and add it to the list */ 139 xx = cache_object_p->i_nextfscacheid; 140 fscache_object_p = cfsd_fscache_create(idp, dirp, xx); 141 cache_fscachelist_add(cache_object_p, fscache_object_p); 142 } else { 143 /* don't do any more if already mounted */ 144 fscache_lock(fscache_object_p); 145 if (fscache_object_p->i_mounted) { 146 cache_object_p->i_refcnt--; 147 fscache_unlock(fscache_object_p); 148 cache_unlock(cache_object_p); 149 dbug_print(("info", "fscache already mounted")); 150 dbug_leave("subr_add_mount"); 151 return; 152 } 153 fscache_unlock(fscache_object_p); 154 } 155 156 fscache_lock(fscache_object_p); 157 fscache_object_p->i_refcnt++; 158 fscache_unlock(fscache_object_p); 159 cache_unlock(cache_object_p); 160 161 /* init the fscache object with mount information */ 162 fscache_lock(fscache_object_p); 163 fscache_setup(fscache_object_p); 164 165 /* start the disconnect thread if necessary */ 166 if (fscache_object_p->i_disconnectable && 167 fscache_object_p->i_mounted && 168 (fscache_object_p->i_threaded == 0) && 169 (strcmp(fscache_object_p->i_name, "rootcache") != 0)) { 170 fscache_object_p->i_refcnt++; 171 fscache_object_p->i_threaded = 1; 172 xx = thr_create(NULL, 0, subr_mount_thread, fscache_object_p, 173 THR_DETACHED | THR_NEW_LWP, &new_thread); 174 if (xx) { 175 /* XXX cachefs kmod cannot allow transition */ 176 dbug_print(("error", "mount thr_create failed %d", xx)); 177 fscache_object_p->i_refcnt--; 178 fscache_object_p->i_threaded = 0; 179 } 180 fscache_object_p->i_threadid = new_thread; 181 } 182 fscache_object_p->i_refcnt--; 183 fscache_unlock(fscache_object_p); 184 185 cache_lock(cache_object_p); 186 cache_object_p->i_refcnt--; 187 cache_unlock(cache_object_p); 188 dbug_leave("subr_add_mount"); 189 } 190 191 /* 192 * ------------------------------------------------------------ 193 * subr_mount_thread 194 * 195 * Description: 196 * Called when a thread is created via thr_create to process 197 * an fscache. 198 * Arguments: 199 * datap ptr to cfsd_fscache to process 200 * Returns: 201 * Returns NULL. 202 * Preconditions: 203 * precond(datap) 204 */ 205 void * 206 subr_mount_thread(void *datap) 207 { 208 cfsd_fscache_object_t *fscache_object_p; 209 210 dbug_enter("subr_mount_thread"); 211 dbug_precond(datap); 212 213 fscache_object_p = (cfsd_fscache_object_t *)datap; 214 215 fscache_process(fscache_object_p); 216 217 fscache_lock(fscache_object_p); 218 219 /* close down the message file descriptor */ 220 if (fscache_object_p->i_ofd >= 0) { 221 if (close(fscache_object_p->i_ofd)) 222 dbug_print(("error", "cannot close fscache fd error %d", 223 errno)); 224 fscache_object_p->i_ofd = -1; 225 } 226 227 fscache_object_p->i_threaded = 0; 228 fscache_object_p->i_refcnt--; 229 fscache_unlock(fscache_object_p); 230 231 dbug_leave("subr_mount_thread"); 232 return (NULL); 233 } 234 235 /* 236 * ------------------------------------------------------------ 237 * subr_cache_setup 238 * 239 * Description: 240 * Called once when the daemon starts up to get the current state 241 * of caches reflected in the daemon. 242 * Arguments: 243 * allp 244 * Returns: 245 * Preconditions: 246 * precond(allp) 247 */ 248 void 249 subr_cache_setup(cfsd_all_object_t *all_object_p) 250 { 251 cfsd_cache_object_t *cache_object_p; 252 int fixcachefstab = 0; 253 int xx; 254 FILE *fin; 255 char buf[MAXPATHLEN]; 256 struct mnttab minfo; 257 struct mnttab mpref; 258 char *cp; 259 char *xcp; 260 struct vfstab vinfo; 261 struct vfstab vpref; 262 size_t index; 263 int lockfd; 264 DIR *dirp; 265 char pathname[MAXPATHLEN]; 266 int len; 267 struct dirent64 *entp; 268 struct stat64 sinfo; 269 270 dbug_enter("subr_cache_setup"); 271 dbug_precond(all_object_p); 272 273 all_lock(all_object_p); 274 275 /* find all the caches indicated in the CACHEFSTAB file */ 276 fin = fopen(CACHEFSTAB, "r"); 277 if (fin == NULL) { 278 dbug_print(("info", "%s does not exist", CACHEFSTAB)); 279 } else { 280 while (fgets(buf, sizeof (buf), fin) != NULL) { 281 if (strlen(buf) == 1) 282 continue; 283 /* 284 * if the line did not fit in the buffer 285 * it is invalid (i.e. no newline char) 286 */ 287 dbug_precond(buf[(strlen(buf) - 1)] == '\n'); 288 if (buf[(strlen(buf) - 1)] != '\n') { 289 #if 0 290 /* 291 * if the line is invalid read until 292 * you get to the next line. 293 * we only need to do this if we are 294 * going to continue 295 */ 296 do { 297 cp = fgets(buf, sizeof (buf), fin); 298 } while ((cp != NULL) && 299 (buf[(strlen(buf) - 1)] != '\n')); 300 #endif 301 break; 302 } 303 buf[strlen(buf) - 1] = '\0'; 304 dbug_print(("info", "cachefstab cache \"%s\"", buf)); 305 cache_object_p = all_cachelist_find(all_object_p, buf); 306 if (cache_object_p == NULL) { 307 /* make the cache object */ 308 cache_object_p = cfsd_cache_create(); 309 xx = all_object_p->i_nextcacheid; 310 xx = cache_setup(cache_object_p, buf, xx); 311 if (xx == 0) { 312 cfsd_cache_destroy(cache_object_p); 313 fixcachefstab++; 314 } else { 315 all_cachelist_add(all_object_p, 316 cache_object_p); 317 } 318 } else { 319 fixcachefstab++; 320 } 321 } 322 if (fclose(fin)) 323 dbug_print(("err", "cannot close %s, %d", 324 CACHEFSTAB, errno)); 325 } 326 327 /* read the mnttab file looking for caches we may have missed */ 328 fin = fopen(MNTTAB, "r"); 329 if (fin == NULL) { 330 dbug_print(("info", "%s does not exist", MNTTAB)); 331 } else { 332 mpref.mnt_special = NULL; 333 mpref.mnt_mountp = NULL; 334 mpref.mnt_fstype = "cachefs"; 335 mpref.mnt_mntopts = NULL; 336 mpref.mnt_time = NULL; 337 while ((xx = getmntany(fin, &minfo, &mpref)) != -1) { 338 if (xx != 0) 339 continue; 340 cp = hasmntopt(&minfo, "cachedir="); 341 if (cp == NULL) 342 cp = "/cache"; /* XXX define in mount.c */ 343 else { 344 cp += 9; 345 xcp = strchr(cp, ','); 346 if (xcp) 347 *xcp = '\0'; 348 } 349 dbug_print(("info", "mnttab cache \"%s\"", cp)); 350 cache_object_p = all_cachelist_find(all_object_p, cp); 351 if (cache_object_p == NULL) { 352 /* make the cache object */ 353 cache_object_p = cfsd_cache_create(); 354 xx = all_object_p->i_nextcacheid; 355 xx = cache_setup(cache_object_p, cp, xx); 356 if (xx == 0) { 357 cfsd_cache_destroy(cache_object_p); 358 fixcachefstab++; 359 } else { 360 all_cachelist_add(all_object_p, 361 cache_object_p); 362 } 363 } else { 364 fixcachefstab++; 365 } 366 } 367 if (fclose(fin)) 368 dbug_print(("err", "cannot close %s, %d", 369 MNTTAB, errno)); 370 } 371 372 /* read the vfstab file looking for caches we may have missed */ 373 fin = fopen(VFSTAB, "r"); 374 if (fin == NULL) { 375 dbug_print(("info", "%s does not exist", VFSTAB)); 376 } else { 377 vpref.vfs_special = NULL; 378 vpref.vfs_fsckdev = NULL; 379 vpref.vfs_mountp = NULL; 380 vpref.vfs_fstype = "cachefs"; 381 vpref.vfs_fsckpass = NULL; 382 vpref.vfs_automnt = NULL; 383 vpref.vfs_mntopts = NULL; 384 while ((xx = getvfsany(fin, &vinfo, &vpref)) != -1) { 385 if (xx != 0) 386 continue; 387 cp = strstr(vinfo.vfs_mntopts, "cachedir="); 388 if (cp == NULL) 389 cp = "/cache"; /* XXX define in mount.c */ 390 else { 391 cp += 9; 392 xcp = strchr(cp, ','); 393 if (xcp) 394 *xcp = '\0'; 395 } 396 dbug_print(("info", "vfstab cache \"%s\"", cp)); 397 cache_object_p = all_cachelist_find(all_object_p, cp); 398 if (cache_object_p == NULL) { 399 /* make the cache object */ 400 cache_object_p = cfsd_cache_create(); 401 xx = all_object_p->i_nextcacheid; 402 xx = cache_setup(cache_object_p, cp, xx); 403 if (xx == 0) { 404 cfsd_cache_destroy(cache_object_p); 405 } else { 406 all_cachelist_add(all_object_p, 407 cache_object_p); 408 fixcachefstab++; 409 } 410 } 411 } 412 if (fclose(fin)) 413 dbug_print(("err", "cannot close %s, %d", 414 VFSTAB, errno)); 415 } 416 417 /* fix up the CACHEFSTAB file if it is out of date */ 418 if (fixcachefstab) 419 all_cachefstab_update(all_object_p); 420 421 /* 422 * now for each cache we found, 423 * find all the file systems in the cache 424 */ 425 for (index = 0; index < all_object_p->i_cachecount; index++) { 426 cache_object_p = all_cachelist_at(all_object_p, index); 427 dbug_assert(cache_object_p); 428 cache_lock(cache_object_p); 429 cache_object_p->i_refcnt++; 430 cache_unlock(cache_object_p); 431 all_unlock(all_object_p); 432 433 /* fix up the cache if necessary */ 434 xx = subr_fsck_cache(cache_object_p->i_cachedir); 435 if (xx != 0) { 436 dbug_print(("error", "could not fix up cache %d", 437 cache_object_p->i_cachedir)); 438 all_lock(all_object_p); 439 cache_lock(cache_object_p); 440 cache_object_p->i_refcnt--; 441 cache_unlock(cache_object_p); 442 continue; 443 } 444 445 /* lock out activity on the cache */ 446 lockfd = cachefs_dir_lock(cache_object_p->i_cachedir, 0); 447 if (lockfd < 0) { 448 dbug_print(("error", "cannot aquire cache lock on %s", 449 cache_object_p->i_cachedir)); 450 all_lock(all_object_p); 451 cache_lock(cache_object_p); 452 cache_object_p->i_refcnt--; 453 cache_unlock(cache_object_p); 454 continue; 455 } 456 457 /* open the cache directory */ 458 dirp = opendir(cache_object_p->i_cachedir); 459 if (dirp == NULL) { 460 dbug_print(("error", "cannot open dir %s", 461 cache_object_p->i_cachedir)); 462 cachefs_dir_unlock(lockfd); 463 all_lock(all_object_p); 464 cache_lock(cache_object_p); 465 cache_object_p->i_refcnt--; 466 cache_unlock(cache_object_p); 467 continue; 468 } 469 470 strlcpy(pathname, cache_object_p->i_cachedir, 471 sizeof (pathname)); 472 strlcat(pathname, "/", sizeof (pathname)); 473 len = strlen(pathname); 474 475 /* read the directory entries */ 476 while ((entp = readdir64(dirp)) != NULL) { 477 /* skip . and .. */ 478 if ((strcmp(entp->d_name, ".") == 0) || 479 (strcmp(entp->d_name, "..") == 0)) 480 continue; 481 482 pathname[len] = '\0'; 483 strlcat(pathname, entp->d_name, sizeof (pathname)); 484 485 /* get info on the file */ 486 xx = lstat64(pathname, &sinfo); 487 if (xx != 0) { 488 dbug_print(("error", 489 "cannot stat %s %d", pathname, errno)); 490 continue; 491 } 492 493 /* skip unless a symbolic link */ 494 if (!S_ISLNK(sinfo.st_mode)) 495 continue; 496 497 /* add this file system to the list */ 498 subr_add_mount(all_object_p, cache_object_p->i_cachedir, 499 entp->d_name); 500 } 501 if (closedir(dirp)) 502 dbug_print(("err", "cannot close dir, %d", errno)); 503 cachefs_dir_unlock(lockfd); 504 all_lock(all_object_p); 505 cache_lock(cache_object_p); 506 cache_object_p->i_refcnt--; 507 cache_unlock(cache_object_p); 508 } 509 510 all_unlock(all_object_p); 511 dbug_leave("subr_cache_setup"); 512 } 513 514 /* 515 * ------------------------------------------------------------ 516 * subr_fsck_cache 517 * 518 * Description: 519 * Fixes the cache if necessary. 520 * Arguments: 521 * cachedirp 522 * Returns: 523 * Returns 0 for success !0 if the cache is not fixed. 524 * Preconditions: 525 * precond(cachedirp) 526 */ 527 int 528 subr_fsck_cache(const char *cachedirp) 529 { 530 char *fsck_argv[4]; 531 int status = 0; 532 pid_t pid; 533 534 dbug_enter("subr_fsck_cache"); 535 536 dbug_precond(cachedirp); 537 538 fsck_argv[1] = "fsck"; 539 fsck_argv[2] = (char *)cachedirp; 540 fsck_argv[3] = NULL; 541 542 dbug_print(("info", "about to fsck %s", cachedirp)); 543 544 /* fork */ 545 if ((pid = fork()) == -1) { 546 dbug_print(("error", "could not fork fsck %d", errno)); 547 dbug_leave("subr_fsck_cache"); 548 return (1); 549 } 550 551 if (pid == 0) { 552 /* do the fsck */ 553 subr_doexec("cachefs", fsck_argv, "fsck"); 554 } else { 555 /* wait for the child to exit */ 556 if (waitpid(pid, &status, 0) == -1) { 557 dbug_print(("error", "fsck wait failed %d", errno)); 558 dbug_leave("subr_fsck_cache"); 559 return (1); 560 } 561 562 if (!WIFEXITED(status)) { 563 dbug_print(("error", "fsck did not exit")); 564 dbug_leave("subr_fsck_cache"); 565 return (1); 566 } 567 568 if (WEXITSTATUS(status) != 0) { 569 dbug_print(("error", "fsck failed")); 570 dbug_leave("subr_fsck_cache"); 571 return (1); 572 } 573 } 574 dbug_leave("subr_fsck_cache"); 575 return (0); 576 } 577 578 /* 579 * ------------------------------------------------------------ 580 * subr_doexec 581 * 582 * Description: 583 * Execs the specified program with the specified command line arguments. 584 * This function never returns. 585 * Arguments: 586 * fstype type of file system 587 * newargv command line arguments 588 * progp name of program to exec 589 * Returns: 590 * Preconditions: 591 * precond(fstype) 592 * precond(newargv) 593 * precond(progp) 594 */ 595 void 596 subr_doexec(const char *fstype, char *newargv[], const char *progp) 597 { 598 #define VFS_PATH "/usr/lib/fs" 599 #define ALT_PATH "/etc/fs" 600 601 char full_path[MAXPATHLEN]; 602 char alter_path[MAXPATHLEN]; 603 char *vfs_path = VFS_PATH; 604 char *alt_path = ALT_PATH; 605 606 dbug_enter("subr_doexec"); 607 608 dbug_precond(fstype); 609 dbug_precond(newargv); 610 dbug_precond(progp); 611 612 /* build the full pathname of the fstype dependent command. */ 613 snprintf(full_path, sizeof (full_path), "%s/%s/%s", vfs_path, 614 fstype, progp); 615 snprintf(alter_path, sizeof (alter_path), "%s/%s/%s", alt_path, 616 fstype, progp); 617 618 /* if the program exists */ 619 if (access(full_path, X_OK) == 0) { 620 /* invoke the program */ 621 execv(full_path, &newargv[1]); 622 623 /* if wrong permissions */ 624 if (errno == EACCES) { 625 dbug_print(("error", "cannot execute %s %s", 626 full_path, strerror(errno))); 627 } 628 629 #ifdef OBSOLETE 630 /* if it did not work and the shell might make it */ 631 if (errno == ENOEXEC) { 632 newargv[0] = "sh"; 633 newargv[1] = full_path; 634 execv("/sbin/sh", &newargv[0]); 635 } 636 #endif 637 } 638 639 #ifdef OBSOLETE 640 /* try the alternate path */ 641 execv(alter_path, &newargv[1]); 642 643 /* if wrong permissions */ 644 if (errno == EACCES) { 645 dbug_print(("error", "cannot execute %s %s", 646 alter_path, strerror(errno))); 647 } 648 649 /* if it did not work and the shell might make it */ 650 if (errno == ENOEXEC) { 651 newargv[0] = "sh"; 652 newargv[1] = alter_path; 653 execv("/sbin/sh", &newargv[0]); 654 } 655 656 dbug_print(("error", "operation not applicable to FSType %s", fstype)); 657 #endif 658 dbug_leave("subr_doexec"); 659 _exit(1); 660 } 661 662 /* 663 * ------------------------------------------------------------ 664 * pr_err 665 * 666 * Description: 667 * Arguments: 668 * fmt 669 * Returns: 670 * Preconditions: 671 * precond(fmt) 672 */ 673 void 674 pr_err(char *fmt, ...) 675 { 676 va_list ap; 677 678 va_start(ap, fmt); 679 (void) fprintf(stderr, "cachefsd -F cachefs: "); 680 (void) vfprintf(stderr, fmt, ap); 681 (void) fprintf(stderr, "\n"); 682 va_end(ap); 683 } 684 685 686 /* 687 * subr_strdup 688 * 689 * Description: 690 * Returns the string dupped. Returns NULL if passed NULL. 691 * Calls new to allocate memory. 692 * Arguments: 693 * strp 694 * Returns: 695 * Preconditions: 696 */ 697 char * 698 subr_strdup(const char *strp) 699 { 700 char *retp = NULL; 701 int len; 702 703 if (strp) { 704 len = strlen(strp) + 1; 705 retp = cfsd_calloc(len); 706 if (retp) 707 strlcpy(retp, strp, len); 708 } 709 return (retp); 710 } 711 /* 712 * ----------------------------------------------------------------- 713 * cfsd_calloc 714 * 715 * Description: 716 * allocates memory of a given size, will retry if error 717 * Arguments: 718 * size 719 * Returns: 720 * pointer to memory 721 * Preconditions: 722 * precond(size) 723 */ 724 725 void * 726 cfsd_calloc(int size) 727 { 728 void *alloc_ptr; 729 730 dbug_enter("cfsd_calloc"); 731 dbug_precond(size); 732 733 /* allocate memory, if calloc fails sleep and retry */ 734 while ((alloc_ptr = calloc(size, 1)) == NULL) { 735 cfsd_sleep(5); 736 } 737 738 dbug_leave("cfsd_calloc"); 739 return (alloc_ptr); 740 } 741 /* 742 * ----------------------------------------------------------------- 743 * cfsd_free 744 * 745 * Description: 746 * frees memory allocated from cfsd_calloc 747 * Arguments: 748 * pointer to memeory 749 * Returns: 750 * none 751 * Preconditions: 752 * precond(size) 753 */ 754 755 void 756 cfsd_free(void *free_ptr) 757 { 758 dbug_enter("cfsd_free"); 759 dbug_precond(free_ptr); 760 761 /* free memory */ 762 if (free_ptr) 763 free(free_ptr); 764 765 dbug_leave("cfsd_free"); 766 } 767 /* 768 * ----------------------------------------------------------------- 769 * cfsd_sleep 770 * 771 * Description: 772 * A reimplemenation of the sleep(3c) function call using 773 * cond_timedwait. 774 * Problem withe sleep(3c) hanging. May return early. 775 * Arguments: 776 * sec number of seconds to sleep for 777 * Returns: 778 * Preconditions: 779 */ 780 781 void 782 cfsd_sleep(int sec) 783 { 784 cond_t cv; 785 mutex_t mt; 786 timestruc_t reltime; 787 788 dbug_enter("cfsd_sleep"); 789 790 if (sec > 0) { 791 mutex_init(&mt, USYNC_THREAD, NULL); 792 cond_init(&cv, USYNC_THREAD, 0); 793 794 reltime.tv_sec = sec; 795 reltime.tv_nsec = 0; 796 797 mutex_lock(&mt); 798 cond_reltimedwait(&cv, &mt, &reltime); 799 mutex_unlock(&mt); 800 801 cond_destroy(&cv); 802 mutex_destroy(&mt); 803 } 804 dbug_leave("cfsd_sleep"); 805 } 806