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 (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  27 /*        All Rights Reserved   */
  28 
  29 /*
  30  * University Copyright- Copyright (c) 1982, 1986, 1988
  31  * The Regents of the University of California
  32  * All Rights Reserved
  33  *
  34  * University Acknowledgment- Portions of this document are derived from
  35  * software developed by the University of California, Berkeley, and its
  36  * contributors.
  37  */
  38 
  39 /*
  40  * Copyright (c) 2012 by Delphix. All rights reserved.
  41  */
  42 
  43 #pragma ident   "%Z%%M% %I%     %E% SMI"
  44 
  45 /*
  46  * sm_statd.c consists of routines used for the intermediate
  47  * statd implementation(3.2 rpc.statd);
  48  * it creates an entry in "current" directory for each site that it monitors;
  49  * after crash and recovery, it moves all entries in "current"
  50  * to "backup" directory, and notifies the corresponding statd of its recovery.
  51  */
  52 
  53 #include <stdio.h>
  54 #include <stdlib.h>
  55 #include <unistd.h>
  56 #include <string.h>
  57 #include <syslog.h>
  58 #include <netdb.h>
  59 #include <sys/types.h>
  60 #include <sys/stat.h>
  61 #include <sys/file.h>
  62 #include <sys/param.h>
  63 #include <arpa/inet.h>
  64 #include <dirent.h>
  65 #include <rpc/rpc.h>
  66 #include <rpcsvc/sm_inter.h>
  67 #include <rpcsvc/nsm_addr.h>
  68 #include <errno.h>
  69 #include <memory.h>
  70 #include <signal.h>
  71 #include <synch.h>
  72 #include <thread.h>
  73 #include <limits.h>
  74 #include <strings.h>
  75 #include "sm_statd.h"
  76 
  77 
  78 int LOCAL_STATE;
  79 
  80 sm_hash_t       mon_table[MAX_HASHSIZE];
  81 static sm_hash_t        record_table[MAX_HASHSIZE];
  82 static sm_hash_t        recov_q;
  83 
  84 static name_entry *find_name(name_entry **namepp, char *name);
  85 static name_entry *insert_name(name_entry **namepp, char *name,
  86                                 int need_alloc);
  87 static void delete_name(name_entry **namepp, char *name);
  88 static void remove_name(char *name, int op, int startup);
  89 static int statd_call_statd(char *name);
  90 static void pr_name(char *name, int flag);
  91 static void *thr_statd_init();
  92 static void *sm_try();
  93 static void *thr_call_statd(void *);
  94 static void remove_single_name(char *name, char *dir1, char *dir2);
  95 static int move_file(char *fromdir, char *file, char *todir);
  96 static int count_symlinks(char *dir, char *name, int *count);
  97 static char *family2string(sa_family_t family);
  98 
  99 /*
 100  * called when statd first comes up; it searches /etc/sm to gather
 101  * all entries to notify its own failure
 102  */
 103 void
 104 statd_init()
 105 {
 106         struct dirent *dirp;
 107         DIR     *dp;
 108         FILE *fp, *fp_tmp;
 109         int i, tmp_state;
 110         char state_file[MAXPATHLEN+SM_MAXPATHLEN];
 111 
 112         if (debug)
 113                 (void) printf("enter statd_init\n");
 114 
 115         /*
 116          * First try to open the file.  If that fails, try to create it.
 117          * If that fails, give up.
 118          */
 119         if ((fp = fopen(STATE, "r+")) == (FILE *)NULL)
 120                 if ((fp = fopen(STATE, "w+")) == (FILE *)NULL) {
 121                         syslog(LOG_ERR, "can't open %s: %m", STATE);
 122                         exit(1);
 123                 } else
 124                         (void) chmod(STATE, 0644);
 125         if ((fscanf(fp, "%d", &LOCAL_STATE)) == EOF) {
 126                 if (debug >= 2)
 127                         (void) printf("empty file\n");
 128                 LOCAL_STATE = 0;
 129         }
 130 
 131         /*
 132          * Scan alternate paths for largest "state" number
 133          */
 134         for (i = 0; i < pathix; i++) {
 135                 (void) sprintf(state_file, "%s/statmon/state", path_name[i]);
 136                 if ((fp_tmp = fopen(state_file, "r+")) == (FILE *)NULL) {
 137                         if ((fp_tmp = fopen(state_file, "w+"))
 138                                 == (FILE *)NULL) {
 139                                 if (debug)
 140                                     syslog(LOG_ERR,
 141                                         "can't open %s: %m",
 142                                         state_file);
 143                                 continue;
 144                         } else
 145                                 (void) chmod(state_file, 0644);
 146                 }
 147                 if ((fscanf(fp_tmp, "%d", &tmp_state)) == EOF) {
 148                         if (debug)
 149                             syslog(LOG_ERR,
 150                                 "statd: %s: file empty\n", state_file);
 151                         (void) fclose(fp_tmp);
 152                         continue;
 153                 }
 154                 if (tmp_state > LOCAL_STATE) {
 155                         LOCAL_STATE = tmp_state;
 156                         if (debug)
 157                                 (void) printf("Update LOCAL STATE: %d\n",
 158                                                 tmp_state);
 159                 }
 160                 (void) fclose(fp_tmp);
 161         }
 162 
 163         LOCAL_STATE = ((LOCAL_STATE%2) == 0) ? LOCAL_STATE+1 : LOCAL_STATE+2;
 164 
 165         /* IF local state overflows, reset to value 1 */
 166         if (LOCAL_STATE < 0) {
 167                 LOCAL_STATE = 1;
 168         }
 169 
 170         /* Copy the LOCAL_STATE value back to all stat files */
 171         if (fseek(fp, 0, 0) == -1) {
 172                 syslog(LOG_ERR, "statd: fseek failed\n");
 173                 exit(1);
 174         }
 175 
 176         (void) fprintf(fp, "%-10d", LOCAL_STATE);
 177         (void) fflush(fp);
 178         if (fsync(fileno(fp)) == -1) {
 179                 syslog(LOG_ERR, "statd: fsync failed\n");
 180                 exit(1);
 181         }
 182         (void) fclose(fp);
 183 
 184         for (i = 0; i < pathix; i++) {
 185                 (void) sprintf(state_file, "%s/statmon/state", path_name[i]);
 186                 if ((fp_tmp = fopen(state_file, "r+")) == (FILE *)NULL) {
 187                         if ((fp_tmp = fopen(state_file, "w+"))
 188                                 == (FILE *)NULL) {
 189                                 syslog(LOG_ERR,
 190                                     "can't open %s: %m", state_file);
 191                                 continue;
 192                         } else
 193                                 (void) chmod(state_file, 0644);
 194                 }
 195                 (void) fprintf(fp_tmp, "%-10d", LOCAL_STATE);
 196                 (void) fflush(fp_tmp);
 197                 if (fsync(fileno(fp_tmp)) == -1) {
 198                         syslog(LOG_ERR,
 199                             "statd: %s: fsync failed\n", state_file);
 200                         (void) fclose(fp_tmp);
 201                         exit(1);
 202                 }
 203                 (void) fclose(fp_tmp);
 204         }
 205 
 206         if (debug)
 207                 (void) printf("local state = %d\n", LOCAL_STATE);
 208 
 209         if ((mkdir(CURRENT, SM_DIRECTORY_MODE)) == -1) {
 210                 if (errno != EEXIST) {
 211                         syslog(LOG_ERR, "statd: mkdir current, error %m\n");
 212                         exit(1);
 213                 }
 214         }
 215         if ((mkdir(BACKUP, SM_DIRECTORY_MODE)) == -1) {
 216                 if (errno != EEXIST) {
 217                         syslog(LOG_ERR, "statd: mkdir backup, error %m\n");
 218                         exit(1);
 219                 }
 220         }
 221 
 222         /* get all entries in CURRENT into BACKUP */
 223         if ((dp = opendir(CURRENT)) == (DIR *)NULL) {
 224                 syslog(LOG_ERR, "statd: open current directory, error %m\n");
 225                 exit(1);
 226         }
 227 
 228         while ((dirp = readdir(dp)) != NULL) {
 229                 if (strcmp(dirp->d_name, ".") != 0 &&
 230                         strcmp(dirp->d_name, "..") != 0) {
 231                 /* rename all entries from CURRENT to BACKUP */
 232                         (void) move_file(CURRENT, dirp->d_name, BACKUP);
 233                 }
 234         }
 235 
 236         (void) closedir(dp);
 237 
 238         /* Contact hosts' statd */
 239         if (thr_create(NULL, NULL, thr_statd_init, NULL, THR_DETACHED, 0)) {
 240                 syslog(LOG_ERR,
 241                 "statd: unable to create thread for thr_statd_init\n");
 242                 exit(1);
 243         }
 244 }
 245 
 246 /*
 247  * Work thread which contacts hosts' statd.
 248  */
 249 void *
 250 thr_statd_init()
 251 {
 252         struct dirent *dirp;
 253         DIR     *dp;
 254         int num_threads;
 255         int num_join;
 256         int i;
 257         char *name;
 258         char buf[MAXPATHLEN+SM_MAXPATHLEN];
 259 
 260         /* Go thru backup directory and contact hosts */
 261         if ((dp = opendir(BACKUP)) == (DIR *)NULL) {
 262                 syslog(LOG_ERR, "statd: open backup directory, error %m\n");
 263                 exit(1);
 264         }
 265 
 266         /*
 267          * Create "UNDETACHED" threads for each symlink and (unlinked)
 268          * regular file in backup directory to initiate statd_call_statd.
 269          * NOTE: These threads are the only undetached threads in this
 270          * program and thus, the thread id is not needed to join the threads.
 271          */
 272         num_threads = 0;
 273         while ((dirp = readdir(dp)) != NULL) {
 274                 /*
 275                  * If host file is not a symlink, don't bother to
 276                  * spawn a thread for it.  If any link(s) refer to
 277                  * it, the host will be contacted using the link(s).
 278                  * If not, we'll deal with it during the legacy pass.
 279                  */
 280                 (void) sprintf(buf, "%s/%s", BACKUP, dirp->d_name);
 281                 if (is_symlink(buf) == 0) {
 282                         continue;
 283                 }
 284 
 285                 /*
 286                  * If the num_threads has exceeded, wait until
 287                  * a certain amount of threads have finished.
 288                  * Currently, 10% of threads created should be joined.
 289                  */
 290                 if (num_threads > MAX_THR) {
 291                         num_join = num_threads/PERCENT_MINJOIN;
 292                         for (i = 0; i < num_join; i++)
 293                                 thr_join(0, 0, 0);
 294                         num_threads -= num_join;
 295                 }
 296 
 297                 /*
 298                  * If can't alloc name then print error msg and
 299                  * continue to next item on list.
 300                  */
 301                 name = strdup(dirp->d_name);
 302                 if (name == (char *)NULL) {
 303                         syslog(LOG_ERR,
 304                                 "statd: unable to allocate space for name %s\n",
 305                                 dirp->d_name);
 306                         continue;
 307                 }
 308 
 309                 /* Create a thread to do a statd_call_statd for name */
 310                 if (thr_create(NULL, NULL, thr_call_statd,
 311                                         (void *) name, 0, 0)) {
 312                         syslog(LOG_ERR,
 313                 "statd: unable to create thr_call_statd() for name %s.\n",
 314                                 dirp->d_name);
 315                         free(name);
 316                         continue;
 317                 }
 318                 num_threads++;
 319         }
 320 
 321         /*
 322          * Join the other threads created above before processing the
 323          * legacies.  This allows all symlinks and the regular files
 324          * to which they correspond to be processed and deleted.
 325          */
 326         for (i = 0; i < num_threads; i++) {
 327                 thr_join(0, 0, 0);
 328         }
 329 
 330         /*
 331          * The second pass checks for `legacies':  regular files which
 332          * never had symlinks pointing to them at all, just like in the
 333          * good old (pre-1184192 fix) days.  Once a machine has cleaned
 334          * up its legacies they should only reoccur due to catastrophes
 335          * (e.g., severed symlinks).
 336          */
 337         rewinddir(dp);
 338         num_threads = 0;
 339         while ((dirp = readdir(dp)) != NULL) {
 340                 if (strcmp(dirp->d_name, ".") == 0 ||
 341                         strcmp(dirp->d_name, "..") == 0) {
 342                         continue;
 343                 }
 344 
 345                 (void) sprintf(buf, "%s/%s", BACKUP, dirp->d_name);
 346                 if (is_symlink(buf)) {
 347                         /*
 348                          * We probably couldn't reach this host and it's
 349                          * been put on the recovery queue for retry.
 350                          * Skip it and keep looking for regular files.
 351                          */
 352                         continue;
 353                 }
 354 
 355                 if (debug) {
 356                         (void) printf("thr_statd_init: legacy %s\n",
 357                                         dirp->d_name);
 358                 }
 359 
 360                 /*
 361                  * If the number of threads exceeds the maximum, wait
 362                  * for some fraction of them to finish before
 363                  * continuing.
 364                  */
 365                 if (num_threads > MAX_THR) {
 366                         num_join = num_threads/PERCENT_MINJOIN;
 367                         for (i = 0; i < num_join; i++)
 368                                 thr_join(0, 0, 0);
 369                         num_threads -= num_join;
 370                 }
 371 
 372                 /*
 373                  * If can't alloc name then print error msg and
 374                  * continue to next item on list.
 375                  */
 376                 name = strdup(dirp->d_name);
 377                 if (name == (char *)NULL) {
 378                         syslog(LOG_ERR,
 379                         "statd: unable to allocate space for name %s\n",
 380                                 dirp->d_name);
 381                         continue;
 382                 }
 383 
 384                 /* Create a thread to do a statd_call_statd for name */
 385                 if (thr_create(NULL, NULL, thr_call_statd,
 386                                         (void *) name, 0, 0)) {
 387                         syslog(LOG_ERR,
 388                 "statd: unable to create thr_call_statd() for name %s.\n",
 389                                 dirp->d_name);
 390                         free(name);
 391                         continue;
 392                 }
 393                 num_threads++;
 394         }
 395 
 396         (void) closedir(dp);
 397 
 398         /*
 399          * Join the other threads created above before creating thread
 400          * to process items in recovery table.
 401          */
 402         for (i = 0; i < num_threads; i++) {
 403                 thr_join(0, 0, 0);
 404         }
 405 
 406         /*
 407          * Need to only copy /var/statmon/sm.bak to alternate paths, since
 408          * the only hosts in /var/statmon/sm should be the ones currently
 409          * being monitored and already should be in alternate paths as part
 410          * of insert_mon().
 411          */
 412         for (i = 0; i < pathix; i++) {
 413                 (void) sprintf(buf, "%s/statmon/sm.bak", path_name[i]);
 414                 if ((mkdir(buf, SM_DIRECTORY_MODE)) == -1) {
 415                         if (errno != EEXIST)
 416                                 syslog(LOG_ERR, "statd: mkdir %s error %m\n",
 417                                         buf);
 418                         else
 419                                 copydir_from_to(BACKUP, buf);
 420                 } else
 421                         copydir_from_to(BACKUP, buf);
 422         }
 423 
 424 
 425         /*
 426          * Reset the die and in_crash variable and signal other threads
 427          * that have issued an sm_crash and are waiting.
 428          */
 429         mutex_lock(&crash_lock);
 430         die = 0;
 431         in_crash = 0;
 432         mutex_unlock(&crash_lock);
 433         cond_broadcast(&crash_finish);
 434 
 435         if (debug)
 436                 (void) printf("Creating thread for sm_try\n");
 437 
 438         /* Continue to notify statd on hosts that were unreachable. */
 439         if (thr_create(NULL, NULL, sm_try, NULL, THR_DETACHED, 0))
 440                 syslog(LOG_ERR,
 441                         "statd: unable to create thread for sm_try().\n");
 442         thr_exit((void *) 0);
 443 #ifdef lint
 444         return (0);
 445 #endif
 446 }
 447 
 448 /*
 449  * Work thread to make call to statd_call_statd.
 450  */
 451 void *
 452 thr_call_statd(void *namep)
 453 {
 454         char *name = (char *)namep;
 455 
 456         /*
 457          * If statd of name is unreachable, add name to recovery table
 458          * otherwise if statd_call_statd was successful, remove from backup.
 459          */
 460         if (statd_call_statd(name) != 0) {
 461                 int n;
 462                 char *tail;
 463                 char path[MAXPATHLEN];
 464                 /*
 465                  * since we are constructing this pathname below we add
 466                  *  another space for the terminating NULL so we don't
 467                  *  overflow our buffer when we do the readlink
 468                  */
 469                 char rname[MAXNAMELEN + 1];
 470 
 471                 if (debug) {
 472                         (void) printf(
 473                         "statd call failed, inserting %s in recov_q\n", name);
 474                 }
 475                 mutex_lock(&recov_q.lock);
 476                 (void) insert_name(&recov_q.sm_recovhdp, name, 0);
 477                 mutex_unlock(&recov_q.lock);
 478 
 479                 /*
 480                  * If we queued a symlink name in the recovery queue,
 481                  * we now clean up the regular file to which it referred.
 482                  * This may leave a severed symlink if multiple links
 483                  * referred to one regular file; this is unaesthetic but
 484                  * it works.  The big benefit is that it prevents us
 485                  * from recovering the same host twice (as symlink and
 486                  * as regular file) needlessly, usually on separate reboots.
 487                  */
 488                 (void) strcpy(path, BACKUP);
 489                 (void) strcat(path, "/");
 490                 (void) strcat(path, name);
 491                 if (is_symlink(path)) {
 492                         n = readlink(path, rname, MAXNAMELEN);
 493                         if (n <= 0) {
 494                                 if (debug >= 2) {
 495                                         (void) printf(
 496                                         "thr_call_statd: can't read link %s\n",
 497                                                         path);
 498                                 }
 499                         } else {
 500                                 rname[n] = '\0';
 501 
 502                                 tail = strrchr(path, '/') + 1;
 503 
 504                                 if ((strlen(BACKUP) + strlen(rname) + 2) <=
 505                                     MAXPATHLEN) {
 506                                         (void) strcpy(tail, rname);
 507                                         delete_file(path);
 508                                 } else if (debug) {
 509                                         printf("thr_call_statd: path over"
 510                                             "maxpathlen!\n");
 511                                 }
 512                         }
 513 
 514                 }
 515 
 516                 if (debug)
 517                         pr_name(name, 0);
 518 
 519         } else {
 520                 /*
 521                  * If `name' is an IP address symlink to a name file,
 522                  * remove it now.  If it is the last such symlink,
 523                  * remove the name file as well.  Regular files with
 524                  * no symlinks to them are assumed to be legacies and
 525                  * are removed as well.
 526                  */
 527                 remove_name(name, 1, 1);
 528                 free(name);
 529         }
 530         thr_exit((void *) 0);
 531 #ifdef lint
 532         return (0);
 533 #endif
 534 }
 535 
 536 /*
 537  * Notifies the statd of host specified by name to indicate that
 538  * state has changed for this server.
 539  */
 540 static int
 541 statd_call_statd(name)
 542         char *name;
 543 {
 544         enum clnt_stat clnt_stat;
 545         struct timeval tottimeout;
 546         CLIENT *clnt;
 547         char *name_or_addr;
 548         stat_chge ntf;
 549         int i;
 550         int rc;
 551         int dummy1, dummy2, dummy3, dummy4;
 552         char ascii_addr[MAXNAMELEN];
 553         size_t unq_len;
 554 
 555         ntf.mon_name = hostname;
 556         ntf.state = LOCAL_STATE;
 557         if (debug)
 558                 (void) printf("statd_call_statd at %s\n", name);
 559 
 560         /*
 561          * If it looks like an ASCII <address family>.<address> specifier,
 562          * strip off the family - we just want the address when obtaining
 563          * a client handle.
 564          * If it's anything else, just pass it on to create_client().
 565          */
 566         unq_len = strcspn(name, ".");
 567 
 568         if ((strncmp(name, SM_ADDR_IPV4, unq_len) == 0) ||
 569                 (strncmp(name, SM_ADDR_IPV6, unq_len) == 0)) {
 570                 name_or_addr = strchr(name, '.') + 1;
 571         } else {
 572                 name_or_addr = name;
 573         }
 574 
 575         /*
 576          * NOTE: We depend here upon the fact that the RPC client code
 577          * allows us to use ASCII dotted quad `names', i.e. "192.9.200.1".
 578          * This may change in a future release.
 579          */
 580         if (debug) {
 581                 (void) printf("statd_call_statd: calling create_client(%s)\n",
 582                                 name_or_addr);
 583         }
 584 
 585         tottimeout.tv_sec = SM_RPC_TIMEOUT;
 586         tottimeout.tv_usec = 0;
 587 
 588         if ((clnt = create_client(name_or_addr, SM_PROG, SM_VERS, NULL,
 589             &tottimeout)) == NULL) {
 590                 return (-1);
 591         }
 592 
 593         /* Perform notification to client */
 594         rc = 0;
 595         clnt_stat = clnt_call(clnt, SM_NOTIFY, xdr_stat_chge, (char *)&ntf,
 596             xdr_void, NULL, tottimeout);
 597         if (debug) {
 598                 (void) printf("clnt_stat=%s(%d)\n",
 599                         clnt_sperrno(clnt_stat), clnt_stat);
 600         }
 601         if (clnt_stat != (int)RPC_SUCCESS) {
 602                 syslog(LOG_WARNING,
 603                         "statd: cannot talk to statd at %s, %s(%d)\n",
 604                         name_or_addr, clnt_sperrno(clnt_stat), clnt_stat);
 605                 rc = -1;
 606         }
 607 
 608         /* For HA systems and multi-homed hosts */
 609         ntf.state = LOCAL_STATE;
 610         for (i = 0; i < addrix; i++) {
 611                 ntf.mon_name = host_name[i];
 612                 if (debug)
 613                         (void) printf("statd_call_statd at %s\n", name_or_addr);
 614                 clnt_stat = clnt_call(clnt, SM_NOTIFY, xdr_stat_chge,
 615                                         (char *)&ntf, xdr_void, NULL,
 616                                         tottimeout);
 617                 if (clnt_stat != (int)RPC_SUCCESS) {
 618                         syslog(LOG_WARNING,
 619                             "statd: cannot talk to statd at %s, %s(%d)\n",
 620                             name_or_addr, clnt_sperrno(clnt_stat), clnt_stat);
 621                         rc = -1;
 622                 }
 623         }
 624         clnt_destroy(clnt);
 625         return (rc);
 626 }
 627 
 628 /*
 629  * Continues to contact hosts in recovery table that were unreachable.
 630  * NOTE:  There should only be one sm_try thread executing and
 631  * thus locks are not needed for recovery table. Die is only cleared
 632  * after all the hosts has at least been contacted once.  The reader/writer
 633  * lock ensures to finish this code before an sm_crash is started.  Die
 634  * variable will signal it.
 635  */
 636 void *
 637 sm_try()
 638 {
 639         name_entry *nl, *next;
 640         timestruc_t     wtime;
 641         int delay = 0;
 642 
 643         rw_rdlock(&thr_rwlock);
 644         if (mutex_trylock(&sm_trylock))
 645                 goto out;
 646         mutex_lock(&crash_lock);
 647 
 648         while (!die) {
 649                 wtime.tv_sec = delay;
 650                 wtime.tv_nsec = 0;
 651                 /*
 652                  * Wait until signalled to wakeup or time expired.
 653                  * If signalled to be awoken, then a crash has occurred
 654                  * or otherwise time expired.
 655                  */
 656                 if (cond_reltimedwait(&retrywait, &crash_lock, &wtime) == 0) {
 657                         break;
 658                 }
 659 
 660                 /* Exit loop if queue is empty */
 661                 if ((next = recov_q.sm_recovhdp) == NULL)
 662                         break;
 663 
 664                 mutex_unlock(&crash_lock);
 665 
 666                 while (((nl = next) != (name_entry *)NULL) && (!die)) {
 667                         next = next->nxt;
 668                         if (statd_call_statd(nl->name) == 0) {
 669                                 /* remove name from BACKUP */
 670                                 remove_name(nl->name, 1, 0);
 671                                 mutex_lock(&recov_q.lock);
 672                                 /* remove entry from recovery_q */
 673                                 delete_name(&recov_q.sm_recovhdp, nl->name);
 674                                 mutex_unlock(&recov_q.lock);
 675                         } else {
 676                                 /*
 677                                  * Print message only once since unreachable
 678                                  * host can be contacted forever.
 679                                  */
 680                                 if (delay == 0)
 681                                         syslog(LOG_WARNING,
 682                                         "statd: host %s is not responding\n",
 683                                                 nl->name);
 684                         }
 685                 }
 686                 /*
 687                  * Increment the amount of delay before restarting again.
 688                  * The amount of delay should not exceed the MAX_DELAYTIME.
 689                  */
 690                 if (delay <= MAX_DELAYTIME)
 691                         delay += INC_DELAYTIME;
 692                 mutex_lock(&crash_lock);
 693         }
 694 
 695         mutex_unlock(&crash_lock);
 696         mutex_unlock(&sm_trylock);
 697 out:
 698         rw_unlock(&thr_rwlock);
 699         if (debug)
 700                 (void) printf("EXITING sm_try\n");
 701         thr_exit((void *) 0);
 702 #ifdef lint
 703         return (0);
 704 #endif
 705 }
 706 
 707 /*
 708  * Malloc's space and returns the ptr to malloc'ed space. NULL if unsuccessful.
 709  */
 710 char *
 711 xmalloc(len)
 712         unsigned len;
 713 {
 714         char *new;
 715 
 716         if ((new = malloc(len)) == 0) {
 717                 syslog(LOG_ERR, "statd: malloc, error %m\n");
 718                 return ((char *)NULL);
 719         } else {
 720                 (void) memset(new, 0, len);
 721                 return (new);
 722         }
 723 }
 724 
 725 /*
 726  * the following two routines are very similar to
 727  * insert_mon and delete_mon in sm_proc.c, except the structture
 728  * is different
 729  */
 730 static name_entry *
 731 insert_name(namepp, name, need_alloc)
 732         name_entry **namepp;
 733         char *name;
 734         int need_alloc;
 735 {
 736         name_entry *new;
 737 
 738         new = (name_entry *)xmalloc(sizeof (name_entry));
 739         if (new == (name_entry *) NULL)
 740                 return (NULL);
 741 
 742         /* Allocate name when needed which is only when adding to record_t */
 743         if (need_alloc) {
 744                 if ((new->name = strdup(name)) == (char *)NULL) {
 745                         syslog(LOG_ERR, "statd: strdup, error %m\n");
 746                         free(new);
 747                         return (NULL);
 748                 }
 749         } else
 750                 new->name = name;
 751 
 752         new->nxt = *namepp;
 753         if (new->nxt != (name_entry *)NULL)
 754                 new->nxt->prev = new;
 755 
 756         new->prev = (name_entry *) NULL;
 757 
 758         *namepp = new;
 759         if (debug) {
 760                 (void) printf("insert_name: inserted %s at %p\n",
 761                                 name, (void *)namepp);
 762         }
 763 
 764         return (new);
 765 }
 766 
 767 /*
 768  * Deletes name from specified list (namepp).
 769  */
 770 static void
 771 delete_name(namepp, name)
 772         name_entry **namepp;
 773         char *name;
 774 {
 775         name_entry *nl;
 776 
 777         nl = *namepp;
 778         while (nl != (name_entry *)NULL) {
 779                 if (str_cmp_address_specifier(nl->name, name) == 0 ||
 780                     str_cmp_unqual_hostname(nl->name, name) == 0) {
 781                         if (nl->prev != (name_entry *)NULL)
 782                                 nl->prev->nxt = nl->nxt;
 783                         else
 784                                 *namepp = nl->nxt;
 785                         if (nl->nxt != (name_entry *)NULL)
 786                                 nl->nxt->prev = nl->prev;
 787                         free(nl->name);
 788                         free(nl);
 789                         return;
 790                 }
 791                 nl = nl->nxt;
 792         }
 793 }
 794 
 795 /*
 796  * Finds name from specified list (namep).
 797  */
 798 static name_entry *
 799 find_name(namep, name)
 800         name_entry **namep;
 801         char *name;
 802 {
 803         name_entry *nl;
 804 
 805         nl = *namep;
 806 
 807         while (nl != (name_entry *)NULL) {
 808                 if (str_cmp_unqual_hostname(nl->name, name) == 0) {
 809                         return (nl);
 810                 }
 811                 nl = nl->nxt;
 812         }
 813         return ((name_entry *)NULL);
 814 }
 815 
 816 /*
 817  * Creates a file.
 818  */
 819 
 820 int
 821 create_file(name)
 822         char *name;
 823 {
 824         int fd;
 825 
 826         /*
 827          * The file might already exist.  If it does, we ask for only write
 828          * permission, since that's all the file was created with.
 829          */
 830         if ((fd = open(name, O_CREAT | O_WRONLY, S_IWUSR)) == -1) {
 831                 if (errno != EEXIST) {
 832                         syslog(LOG_ERR, "can't open %s: %m", name);
 833                         return (1);
 834                 }
 835         }
 836 
 837         if (debug >= 2)
 838                 (void) printf("%s is created\n", name);
 839         if (close(fd)) {
 840                 syslog(LOG_ERR, "statd: close, error %m\n");
 841                 return (1);
 842         }
 843 
 844         return (0);
 845 }
 846 
 847 /*
 848  * Deletes the file specified by name.
 849  */
 850 void
 851 delete_file(name)
 852         char *name;
 853 {
 854         if (debug >= 2)
 855                 (void) printf("Remove monitor entry %s\n", name);
 856         if (unlink(name) == -1) {
 857                 if (errno != ENOENT)
 858                         syslog(LOG_ERR, "statd: unlink of %s, error %m", name);
 859         }
 860 }
 861 
 862 /*
 863  * Return 1 if file is a symlink, else 0.
 864  */
 865 int
 866 is_symlink(file)
 867         char *file;
 868 {
 869         int error;
 870         struct stat lbuf;
 871 
 872         do {
 873                 bzero((caddr_t)&lbuf, sizeof (lbuf));
 874                 error = lstat(file, &lbuf);
 875         } while (error == EINTR);
 876 
 877         if (error == 0) {
 878                 return ((lbuf.st_mode & S_IFMT) == S_IFLNK);
 879         }
 880 
 881         return (0);
 882 }
 883 
 884 /*
 885  * Moves the file specified by `from' to `to' only if the
 886  * new file is guaranteed to be created (which is presumably
 887  * why we don't just do a rename(2)).  If `from' is a
 888  * symlink, the destination file will be a similar symlink
 889  * in the directory of `to'.
 890  *
 891  * Returns 0 for success, 1 for failure.
 892  */
 893 static int
 894 move_file(fromdir, file, todir)
 895         char *fromdir;
 896         char *file;
 897         char *todir;
 898 {
 899         int n;
 900         char rname[MAXNAMELEN + 1]; /* +1 for the terminating NULL */
 901         char from[MAXPATHLEN];
 902         char to[MAXPATHLEN];
 903 
 904         (void) strcpy(from, fromdir);
 905         (void) strcat(from, "/");
 906         (void) strcat(from, file);
 907         if (is_symlink(from)) {
 908                 /*
 909                  * Dig out the name of the regular file the link points to.
 910                  */
 911                 n = readlink(from, rname, MAXNAMELEN);
 912                 if (n <= 0) {
 913                         if (debug >= 2) {
 914                                 (void) printf("move_file: can't read link %s\n",
 915                                                 from);
 916                         }
 917                         return (1);
 918                 }
 919                 rname[n] = '\0';
 920 
 921                 /*
 922                  * Create the link.
 923                  */
 924                 if (create_symlink(todir, rname, file) != 0) {
 925                         return (1);
 926                 }
 927         } else {
 928                 /*
 929                  * Do what we've always done to move regular files.
 930                  */
 931                 (void) strcpy(to, todir);
 932                 (void) strcat(to, "/");
 933                 (void) strcat(to, file);
 934                 if (create_file(to) != 0) {
 935                         return (1);
 936                 }
 937         }
 938 
 939         /*
 940          * Remove the old file if we've created the new one.
 941          */
 942         if (unlink(from) < 0) {
 943                 syslog(LOG_ERR, "move_file: unlink of %s, error %m", from);
 944                 return (1);
 945         }
 946 
 947         return (0);
 948 }
 949 
 950 /*
 951  * Create a symbolic link named `lname' to regular file `rname'.
 952  * Both files should be in directory `todir'.
 953  */
 954 int
 955 create_symlink(todir, rname, lname)
 956         char *todir;
 957         char *rname;
 958         char *lname;
 959 {
 960         int error;
 961         char lpath[MAXPATHLEN];
 962 
 963         /*
 964          * Form the full pathname of the link.
 965          */
 966         (void) strcpy(lpath, todir);
 967         (void) strcat(lpath, "/");
 968         (void) strcat(lpath, lname);
 969 
 970         /*
 971          * Now make the new symlink ...
 972          */
 973         if (symlink(rname, lpath) < 0) {
 974                 error = errno;
 975                 if (error != 0 && error != EEXIST) {
 976                         if (debug >= 2) {
 977                                 (void) printf(
 978                                 "create_symlink: can't link %s/%s -> %s\n",
 979                                         todir, lname, rname);
 980                         }
 981                         return (1);
 982                 }
 983         }
 984 
 985         if (debug) {
 986                 if (error == EEXIST) {
 987                         (void) printf("link %s/%s -> %s already exists\n",
 988                                 todir, lname, rname);
 989                 } else {
 990                         (void) printf("created link %s/%s -> %s\n",
 991                                 todir, lname, rname);
 992                 }
 993         }
 994 
 995         return (0);
 996 }
 997 
 998 /*
 999  * remove the name from the specified directory
1000  * op = 0: CURRENT
1001  * op = 1: BACKUP
1002  */
1003 static void
1004 remove_name(char *name, int op, int startup)
1005 {
1006         int i;
1007         char *alt_dir;
1008         char *queue;
1009 
1010         if (op == 0) {
1011                 alt_dir = "statmon/sm";
1012                 queue = CURRENT;
1013         } else {
1014                 alt_dir = "statmon/sm.bak";
1015                 queue = BACKUP;
1016         }
1017 
1018         remove_single_name(name, queue, NULL);
1019         /*
1020          * At startup, entries have not yet been copied to alternate
1021          * directories and thus do not need to be removed.
1022          */
1023         if (startup == 0) {
1024                 for (i = 0; i < pathix; i++) {
1025                         remove_single_name(name, path_name[i], alt_dir);
1026                 }
1027         }
1028 }
1029 
1030 /*
1031  * Remove the name from the specified directory, which is dir1/dir2 or
1032  * dir1, depending on whether dir2 is NULL.
1033  */
1034 static void
1035 remove_single_name(char *name, char *dir1, char *dir2)
1036 {
1037         int n, error;
1038         char path[MAXPATHLEN+MAXNAMELEN+SM_MAXPATHLEN]; /* why > MAXPATHLEN? */
1039         char dirpath[MAXPATHLEN];
1040         char rname[MAXNAMELEN + 1]; /* +1 for NULL term */
1041 
1042         if (strlen(name) + strlen(dir1) + (dir2 != NULL ? strlen(dir2) : 0)
1043                         + 3 > MAXPATHLEN) {
1044                 if (dir2 != NULL)
1045                         syslog(LOG_ERR,
1046                                 "statd: pathname too long: %s/%s/%s\n",
1047                                                 dir1, dir2, name);
1048                 else
1049                         syslog(LOG_ERR,
1050                                 "statd: pathname too long: %s/%s\n",
1051                                                 dir1, name);
1052 
1053                 return;
1054         }
1055 
1056         (void) strcpy(path, dir1);
1057         (void) strcat(path, "/");
1058         if (dir2 != NULL) {
1059                 (void) strcat(path, dir2);
1060                 (void) strcat(path, "/");
1061         }
1062         (void) strcpy(dirpath, path);   /* save here - we may need it shortly */
1063         (void) strcat(path, name);
1064 
1065         /*
1066          * Despite the name of this routine :-@), `path' may be a symlink
1067          * to a regular file.  If it is, and if that file has no other
1068          * links to it, we must remove it now as well.
1069          */
1070         if (is_symlink(path)) {
1071                 n = readlink(path, rname, MAXNAMELEN);
1072                 if (n > 0) {
1073                         rname[n] = '\0';
1074 
1075                         if (count_symlinks(dirpath, rname, &n) < 0) {
1076                                 return;
1077                         }
1078 
1079                         if (n == 1) {
1080                                 (void) strcat(dirpath, rname);
1081                                 error = unlink(dirpath);
1082                                 if (debug >= 2) {
1083                                         if (error < 0) {
1084                                                 (void) printf(
1085                                         "remove_name: can't unlink %s\n",
1086                                                         dirpath);
1087                                         } else {
1088                                                 (void) printf(
1089                                         "remove_name: unlinked %s\n",
1090                                                         dirpath);
1091                                         }
1092                                 }
1093                         }
1094                 } else {
1095                         /*
1096                          * Policy: if we can't read the symlink, leave it
1097                          * here for analysis by the system administrator.
1098                          */
1099                         syslog(LOG_ERR,
1100                                 "statd: can't read link %s: %m\n", path);
1101                 }
1102         }
1103 
1104         /*
1105          * If it's a regular file, we can assume all symlinks and the
1106          * files to which they refer have been processed already - just
1107          * fall through to here to remove it.
1108          */
1109         delete_file(path);
1110 }
1111 
1112 /*
1113  * Count the number of symlinks in `dir' which point to `name' (also in dir).
1114  * Passes back symlink count in `count'.
1115  * Returns 0 for success, < 0 for failure.
1116  */
1117 static int
1118 count_symlinks(char *dir, char *name, int *count)
1119 {
1120         int cnt = 0;
1121         int n;
1122         DIR *dp;
1123         struct dirent *dirp;
1124         char lpath[MAXPATHLEN];
1125         char rname[MAXNAMELEN + 1]; /* +1 for term NULL */
1126 
1127         if ((dp = opendir(dir)) == (DIR *)NULL) {
1128                 syslog(LOG_ERR, "count_symlinks: open %s dir, error %m\n",
1129                         dir);
1130                 return (-1);
1131         }
1132 
1133         while ((dirp = readdir(dp)) != NULL) {
1134                 if (strcmp(dirp->d_name, ".") == 0 ||
1135                         strcmp(dirp->d_name, "..") == 0) {
1136                         continue;
1137                 }
1138 
1139                 (void) sprintf(lpath, "%s%s", dir, dirp->d_name);
1140                 if (is_symlink(lpath)) {
1141                         /*
1142                          * Fetch the name of the file the symlink refers to.
1143                          */
1144                         n = readlink(lpath, rname, MAXNAMELEN);
1145                         if (n <= 0) {
1146                                 if (debug >= 2) {
1147                                         (void) printf(
1148                                         "count_symlinks: can't read link %s\n",
1149                                                 lpath);
1150                                 }
1151                                 continue;
1152                         }
1153                         rname[n] = '\0';
1154 
1155                         /*
1156                          * If `rname' matches `name', bump the count.  There
1157                          * may well be multiple symlinks to the same name, so
1158                          * we must continue to process the entire directory.
1159                          */
1160                         if (strcmp(rname, name) == 0) {
1161                                 cnt++;
1162                         }
1163                 }
1164         }
1165 
1166         (void) closedir(dp);
1167 
1168         if (debug) {
1169                 (void) printf("count_symlinks: found %d symlinks\n", cnt);
1170         }
1171         *count = cnt;
1172         return (0);
1173 }
1174 
1175 /*
1176  * Manage the cache of hostnames.  An entry for each host that has recently
1177  * locked a file is kept.  There is an in-ram table (rec_table) and an empty
1178  * file in the file system name space (/var/statmon/sm/<name>).  This
1179  * routine adds (deletes) the name to (from) the in-ram table and the entry
1180  * to (from) the file system name space.
1181  *
1182  * If op == 1 then the name is added to the queue otherwise the name is
1183  * deleted.
1184  */
1185 void
1186 record_name(name, op)
1187         char *name;
1188         int op;
1189 {
1190         name_entry *nl;
1191         int i;
1192         char path[MAXPATHLEN+MAXNAMELEN+SM_MAXPATHLEN];
1193         name_entry **record_q;
1194         unsigned int hash;
1195 
1196         /*
1197          * These names are supposed to be just host names, not paths or
1198          * other arbitrary files.
1199          * manipulating the empty pathname unlinks CURRENT,
1200          * manipulating files with '/' would allow you to create and unlink
1201          * files all over the system; LOG_AUTH, it's a security thing.
1202          * Don't remove the directories . and ..
1203          */
1204         if (name == NULL)
1205                 return;
1206 
1207         if (name[0] == '\0' || strchr(name, '/') != NULL ||
1208                         strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
1209                 syslog(LOG_ERR|LOG_AUTH, "statd: attempt to %s \"%s/%s\"",
1210                         op == 1 ? "create" : "remove", CURRENT, name);
1211                 return;
1212         }
1213 
1214         SMHASH(name, hash);
1215         if (debug) {
1216                 if (op == 1)
1217                         (void) printf("inserting %s at hash %d,\n",
1218                         name, hash);
1219                 else
1220                         (void) printf("deleting %s at hash %d\n", name, hash);
1221                 pr_name(name, 1);
1222         }
1223 
1224 
1225         if (op == 1) { /* insert */
1226                 mutex_lock(&record_table[hash].lock);
1227                 record_q = &record_table[hash].sm_rechdp;
1228                 if ((nl = find_name(record_q, name)) == (name_entry *)NULL) {
1229 
1230                         int     path_len;
1231 
1232                         if ((nl = insert_name(record_q, name, 1)) !=
1233                             (name_entry *) NULL)
1234                                 nl->count++;
1235                         mutex_unlock(&record_table[hash].lock);
1236                         /* make an entry in current directory */
1237 
1238                         path_len = strlen(CURRENT) + strlen(name) + 2;
1239                         if (path_len > MAXPATHLEN) {
1240                                 syslog(LOG_ERR,
1241                                         "statd: pathname too long: %s/%s\n",
1242                                                 CURRENT, name);
1243                                 return;
1244                         }
1245                         (void) strcpy(path, CURRENT);
1246                         (void) strcat(path, "/");
1247                         (void) strcat(path, name);
1248                         (void) create_file(path);
1249                         if (debug) {
1250                                 (void) printf("After insert_name\n");
1251                                 pr_name(name, 1);
1252                         }
1253                         /* make an entry in alternate paths */
1254                         for (i = 0; i < pathix; i++) {
1255                                 path_len = strlen(path_name[i]) +
1256                                                         strlen("/statmon/sm/") +
1257                                                         strlen(name) + 1;
1258 
1259                                 if (path_len > MAXPATHLEN) {
1260                                         syslog(LOG_ERR,
1261                                 "statd: pathname too long: %s/statmon/sm/%s\n",
1262                                                         path_name[i], name);
1263                                         continue;
1264                                 }
1265                                 (void) strcpy(path, path_name[i]);
1266                                 (void) strcat(path, "/statmon/sm/");
1267                                 (void) strcat(path, name);
1268                                 (void) create_file(path);
1269                         }
1270                         return;
1271                 }
1272                 nl->count++;
1273                 mutex_unlock(&record_table[hash].lock);
1274 
1275         } else { /* delete */
1276                 mutex_lock(&record_table[hash].lock);
1277                 record_q = &record_table[hash].sm_rechdp;
1278                 if ((nl = find_name(record_q, name)) == (name_entry *)NULL) {
1279                         mutex_unlock(&record_table[hash].lock);
1280                         return;
1281                 }
1282                 nl->count--;
1283                 if (nl->count == 0) {
1284                         delete_name(record_q, name);
1285                         mutex_unlock(&record_table[hash].lock);
1286                         /* remove this entry from current directory */
1287                         remove_name(name, 0, 0);
1288                 } else
1289                         mutex_unlock(&record_table[hash].lock);
1290                 if (debug) {
1291                         (void) printf("After delete_name \n");
1292                         pr_name(name, 1);
1293                 }
1294         }
1295 }
1296 
1297 /*
1298  * This routine adds a symlink in the form of an ASCII dotted quad
1299  * IP address that is linked to the name already recorded in the
1300  * filesystem name space by record_name().  Enough information is
1301  * (hopefully) provided to support other address types in the future.
1302  * The purpose of this is to cache enough information to contact
1303  * hosts in other domains during server crash recovery (see bugid
1304  * 1184192).
1305  *
1306  * The worst failure mode here is that the symlink is not made, and
1307  * statd falls back to the old buggy behavior.
1308  */
1309 void
1310 record_addr(char *name, sa_family_t family, struct netobj *ah)
1311 {
1312         int i;
1313         int path_len;
1314         char *famstr;
1315         struct in_addr addr;
1316         char *addr6;
1317         char ascii_addr[MAXNAMELEN];
1318         char path[MAXPATHLEN];
1319 
1320         if (family == AF_INET) {
1321                 if (ah->n_len != sizeof (struct in_addr))
1322                         return;
1323                 addr = *(struct in_addr *)ah->n_bytes;
1324         } else if (family == AF_INET6) {
1325                         if (ah->n_len != sizeof (struct in6_addr))
1326                                 return;
1327                         addr6 = (char *)ah->n_bytes;
1328         } else
1329                 return;
1330 
1331         if (debug) {
1332                 if (family == AF_INET)
1333                         (void) printf("record_addr: addr= %x\n", addr.s_addr);
1334                 else if (family == AF_INET6)
1335                         (void) printf("record_addr: addr= %x\n", \
1336                                 ((struct in6_addr *)addr6)->s6_addr);
1337         }
1338 
1339         if (family == AF_INET) {
1340                 if (addr.s_addr == INADDR_ANY ||
1341                     ((addr.s_addr && 0xff000000) == 0)) {
1342                         syslog(LOG_DEBUG,
1343                                 "record_addr: illegal IP address %x\n",
1344                                 addr.s_addr);
1345                         return;
1346                 }
1347         }
1348 
1349         /* convert address to ASCII */
1350         famstr = family2string(family);
1351         if (famstr == NULL) {
1352                 syslog(LOG_DEBUG,
1353                         "record_addr: unsupported address family %d\n",
1354                         family);
1355                 return;
1356         }
1357 
1358         switch (family) {
1359                 char abuf[INET6_ADDRSTRLEN];
1360             case AF_INET:
1361                 (void) sprintf(ascii_addr, "%s.%s", famstr, inet_ntoa(addr));
1362                 break;
1363 
1364             case AF_INET6:
1365                 (void) sprintf(ascii_addr, "%s.%s", famstr,\
1366                     inet_ntop(family, addr6, abuf, sizeof (abuf)));
1367                 break;
1368 
1369             default:
1370                 if (debug) {
1371                         (void) printf(
1372                 "record_addr: family2string supports unknown family %d (%s)\n",
1373                                 family,
1374                                 famstr);
1375                 }
1376                 free(famstr);
1377                 return;
1378         }
1379 
1380         if (debug) {
1381                 (void) printf("record_addr: ascii_addr= %s\n", ascii_addr);
1382         }
1383         free(famstr);
1384 
1385         /*
1386          * Make the symlink in CURRENT.  The `name' file should have
1387          * been created previously by record_name().
1388          */
1389         (void) create_symlink(CURRENT, name, ascii_addr);
1390 
1391         /*
1392          * Similarly for alternate paths.
1393          */
1394         for (i = 0; i < pathix; i++) {
1395                 path_len = strlen(path_name[i]) +
1396                                         strlen("/statmon/sm/") +
1397                                         strlen(name) + 1;
1398 
1399                 if (path_len > MAXPATHLEN) {
1400                         syslog(LOG_ERR,
1401                                 "statd: pathname too long: %s/statmon/sm/%s\n",
1402                                 path_name[i], name);
1403                         continue;
1404                 }
1405                 (void) strcpy(path, path_name[i]);
1406                 (void) strcat(path, "/statmon/sm");
1407                 (void) create_symlink(path, name, ascii_addr);
1408         }
1409 }
1410 
1411 /*
1412  * SM_CRASH - simulate a crash of statd.
1413  */
1414 void
1415 sm_crash()
1416 {
1417         name_entry *nl, *next;
1418         mon_entry *nl_monp, *mon_next;
1419         int k;
1420         my_id *nl_idp;
1421 
1422         for (k = 0; k < MAX_HASHSIZE; k++) {
1423                 mutex_lock(&mon_table[k].lock);
1424                 if ((mon_next = mon_table[k].sm_monhdp) ==
1425                     (mon_entry *) NULL) {
1426                         mutex_unlock(&mon_table[k].lock);
1427                         continue;
1428                 } else {
1429                         while ((nl_monp = mon_next) != (mon_entry *)NULL) {
1430                                 mon_next = mon_next->nxt;
1431                                 nl_idp = &nl_monp->id.mon_id.my_id;
1432                                 free(nl_monp->id.mon_id.mon_name);
1433                                 free(nl_idp->my_name);
1434                                 free(nl_monp);
1435                         }
1436                         mon_table[k].sm_monhdp = (mon_entry *)NULL;
1437                 }
1438                 mutex_unlock(&mon_table[k].lock);
1439         }
1440 
1441         /* Clean up entries in  record table */
1442         for (k = 0; k < MAX_HASHSIZE; k++) {
1443                 mutex_lock(&record_table[k].lock);
1444                 if ((next = record_table[k].sm_rechdp) ==
1445                     (name_entry *) NULL) {
1446                         mutex_unlock(&record_table[k].lock);
1447                         continue;
1448                 } else {
1449                         while ((nl = next) != (name_entry *)NULL) {
1450                                 next = next->nxt;
1451                                 free(nl->name);
1452                                 free(nl);
1453                         }
1454                         record_table[k].sm_rechdp = (name_entry *)NULL;
1455                 }
1456                 mutex_unlock(&record_table[k].lock);
1457         }
1458 
1459         /* Clean up entries in recovery table */
1460         mutex_lock(&recov_q.lock);
1461         if ((next = recov_q.sm_recovhdp) != (name_entry *)NULL) {
1462                 while ((nl = next) != (name_entry *)NULL) {
1463                         next = next->nxt;
1464                         free(nl->name);
1465                         free(nl);
1466                 }
1467                 recov_q.sm_recovhdp = (name_entry *)NULL;
1468         }
1469         mutex_unlock(&recov_q.lock);
1470         statd_init();
1471 }
1472 
1473 /*
1474  * Initialize the hash tables: mon_table, record_table, recov_q and
1475  * locks.
1476  */
1477 void
1478 sm_inithash()
1479 {
1480         int k;
1481 
1482         if (debug)
1483                 (void) printf("Initializing hash tables\n");
1484         for (k = 0; k < MAX_HASHSIZE; k++) {
1485                 mon_table[k].sm_monhdp = (mon_entry *)NULL;
1486                 record_table[k].sm_rechdp = (name_entry *)NULL;
1487                 mutex_init(&mon_table[k].lock, USYNC_THREAD, NULL);
1488                 mutex_init(&record_table[k].lock, USYNC_THREAD, NULL);
1489         }
1490         mutex_init(&recov_q.lock, USYNC_THREAD, NULL);
1491         recov_q.sm_recovhdp = (name_entry *)NULL;
1492 
1493 }
1494 
1495 /*
1496  * Maps a socket address family to a name string, or NULL if the family
1497  * is not supported by statd.
1498  * Caller is responsible for freeing storage used by result string, if any.
1499  */
1500 static char *
1501 family2string(sa_family_t family)
1502 {
1503         char *rc;
1504 
1505         switch (family) {
1506         case AF_INET:
1507                 rc = strdup(SM_ADDR_IPV4);
1508                 break;
1509 
1510         case AF_INET6:
1511                 rc = strdup(SM_ADDR_IPV6);
1512                 break;
1513 
1514         default:
1515                 rc = NULL;
1516                 break;
1517         }
1518 
1519         return (rc);
1520 }
1521 
1522 /*
1523  * Prints out list in record_table if flag is 1 otherwise
1524  * prints out each list in recov_q specified by name.
1525  */
1526 static void
1527 pr_name(name, flag)
1528         char *name;
1529         int flag;
1530 {
1531         name_entry *nl;
1532         unsigned int hash;
1533 
1534         if (!debug)
1535                 return;
1536         if (flag) {
1537                 SMHASH(name, hash);
1538                 (void) printf("*****record_q: ");
1539                 mutex_lock(&record_table[hash].lock);
1540                 nl = record_table[hash].sm_rechdp;
1541                 while (nl != (name_entry *)NULL) {
1542                         (void) printf("(%x), ", (int)nl);
1543                         nl = nl->nxt;
1544                 }
1545                 mutex_unlock(&record_table[hash].lock);
1546         } else {
1547                 (void) printf("*****recovery_q: ");
1548                 mutex_lock(&recov_q.lock);
1549                 nl = recov_q.sm_recovhdp;
1550                 while (nl != (name_entry *)NULL) {
1551                         (void) printf("(%x), ", (int)nl);
1552                         nl = nl->nxt;
1553                 }
1554                 mutex_unlock(&recov_q.lock);
1555 
1556         }
1557         (void) printf("\n");
1558 }