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