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 }