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
subr_add_mount(cfsd_all_object_t * all_object_p,const char * dirp,const char * idp)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 *
subr_mount_thread(void * datap)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
subr_cache_setup(cfsd_all_object_t * all_object_p)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
subr_fsck_cache(const char * cachedirp)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
subr_doexec(const char * fstype,char * newargv[],const char * progp)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
pr_err(char * fmt,...)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 *
subr_strdup(const char * strp)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 *
cfsd_calloc(int size)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
cfsd_free(void * free_ptr)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
cfsd_sleep(int sec)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