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