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