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