Print this page
195 Need replacement for nfs/lockd+klm
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Jeremy Jones <jeremy@delphix.com>
Reviewed by: Jeff Biseda <jbiseda@delphix.com>


  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>


 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);


 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 


 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


 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


 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);


 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;


 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);


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);


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 }


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);


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++) {




  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>


 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);


 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 


 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


 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


 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);


 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;


 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);


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);


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 }


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);


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++) {