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