xref: /onnv-gate/usr/src/cmd/fs.d/nfs/statd/sm_statd.c (revision 0:68f95e015346)
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