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