xref: /titanic_41/usr/src/cmd/fs.d/nfs/statd/sm_statd.c (revision 8200fe25ffab8b2032d046c88710a949f361b700)
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;
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 	while ((dirp = readdir(dp)) != NULL) {
226 		if (strcmp(dirp->d_name, ".") != 0 &&
227 			strcmp(dirp->d_name, "..") != 0) {
228 		/* rename all entries from CURRENT to BACKUP */
229 			(void) move_file(CURRENT, dirp->d_name, BACKUP);
230 		}
231 	}
232 
233 	(void) closedir(dp);
234 
235 	/* Contact hosts' statd */
236 	if (thr_create(NULL, NULL, thr_statd_init, NULL, THR_DETACHED, 0)) {
237 		syslog(LOG_ERR,
238 		"statd: unable to create thread for thr_statd_init\n");
239 		exit(1);
240 	}
241 }
242 
243 /*
244  * Work thread which contacts hosts' statd.
245  */
246 void *
247 thr_statd_init()
248 {
249 	struct dirent *dirp;
250 	DIR 	*dp;
251 	int num_threads;
252 	int num_join;
253 	int i;
254 	char *name;
255 	char buf[MAXPATHLEN+SM_MAXPATHLEN];
256 
257 	/* Go thru backup directory and contact hosts */
258 	if ((dp = opendir(BACKUP)) == (DIR *)NULL) {
259 		syslog(LOG_ERR, "statd: open backup directory, error %m\n");
260 		exit(1);
261 	}
262 
263 	/*
264 	 * Create "UNDETACHED" threads for each symlink and (unlinked)
265 	 * regular file in backup directory to initiate statd_call_statd.
266 	 * NOTE: These threads are the only undetached threads in this
267 	 * program and thus, the thread id is not needed to join the threads.
268 	 */
269 	num_threads = 0;
270 	while ((dirp = readdir(dp)) != NULL) {
271 		/*
272 		 * If host file is not a symlink, don't bother to
273 		 * spawn a thread for it.  If any link(s) refer to
274 		 * it, the host will be contacted using the link(s).
275 		 * If not, we'll deal with it during the legacy pass.
276 		 */
277 		(void) sprintf(buf, "%s/%s", BACKUP, dirp->d_name);
278 		if (is_symlink(buf) == 0) {
279 			continue;
280 		}
281 
282 		/*
283 		 * If the num_threads has exceeded, wait until
284 		 * a certain amount of threads have finished.
285 		 * Currently, 10% of threads created should be joined.
286 		 */
287 		if (num_threads > MAX_THR) {
288 			num_join = num_threads/PERCENT_MINJOIN;
289 			for (i = 0; i < num_join; i++)
290 				thr_join(0, 0, 0);
291 			num_threads -= num_join;
292 		}
293 
294 		/*
295 		 * If can't alloc name then print error msg and
296 		 * continue to next item on list.
297 		 */
298 		name = strdup(dirp->d_name);
299 		if (name == (char *)NULL) {
300 			syslog(LOG_ERR,
301 				"statd: unable to allocate space for name %s\n",
302 				dirp->d_name);
303 			continue;
304 		}
305 
306 		/* Create a thread to do a statd_call_statd for name */
307 		if (thr_create(NULL, NULL, thr_call_statd,
308 					(void *) name, 0, 0)) {
309 			syslog(LOG_ERR,
310 		"statd: unable to create thr_call_statd() for name %s.\n",
311 				dirp->d_name);
312 			free(name);
313 			continue;
314 		}
315 		num_threads++;
316 	}
317 
318 	/*
319 	 * Join the other threads created above before processing the
320 	 * legacies.  This allows all symlinks and the regular files
321 	 * to which they correspond to be processed and deleted.
322 	 */
323 	for (i = 0; i < num_threads; i++) {
324 		thr_join(0, 0, 0);
325 	}
326 
327 	/*
328 	 * The second pass checks for `legacies':  regular files which
329 	 * never had symlinks pointing to them at all, just like in the
330 	 * good old (pre-1184192 fix) days.  Once a machine has cleaned
331 	 * up its legacies they should only reoccur due to catastrophes
332 	 * (e.g., severed symlinks).
333 	 */
334 	rewinddir(dp);
335 	num_threads = 0;
336 	while ((dirp = readdir(dp)) != NULL) {
337 		if (strcmp(dirp->d_name, ".") == 0 ||
338 			strcmp(dirp->d_name, "..") == 0) {
339 			continue;
340 		}
341 
342 		(void) sprintf(buf, "%s/%s", BACKUP, dirp->d_name);
343 		if (is_symlink(buf)) {
344 			/*
345 			 * We probably couldn't reach this host and it's
346 			 * been put on the recovery queue for retry.
347 			 * Skip it and keep looking for regular files.
348 			 */
349 			continue;
350 		}
351 
352 		if (debug) {
353 			(void) printf("thr_statd_init: legacy %s\n",
354 					dirp->d_name);
355 		}
356 
357 		/*
358 		 * If the number of threads exceeds the maximum, wait
359 		 * for some fraction of them to finish before
360 		 * continuing.
361 		 */
362 		if (num_threads > MAX_THR) {
363 			num_join = num_threads/PERCENT_MINJOIN;
364 			for (i = 0; i < num_join; i++)
365 				thr_join(0, 0, 0);
366 			num_threads -= num_join;
367 		}
368 
369 		/*
370 		 * If can't alloc name then print error msg and
371 		 * continue to next item on list.
372 		 */
373 		name = strdup(dirp->d_name);
374 		if (name == (char *)NULL) {
375 			syslog(LOG_ERR,
376 			"statd: unable to allocate space for name %s\n",
377 				dirp->d_name);
378 			continue;
379 		}
380 
381 		/* Create a thread to do a statd_call_statd for name */
382 		if (thr_create(NULL, NULL, thr_call_statd,
383 					(void *) name, 0, 0)) {
384 			syslog(LOG_ERR,
385 		"statd: unable to create thr_call_statd() for name %s.\n",
386 				dirp->d_name);
387 			free(name);
388 			continue;
389 		}
390 		num_threads++;
391 	}
392 
393 	(void) closedir(dp);
394 
395 	/*
396 	 * Join the other threads created above before creating thread
397 	 * to process items in recovery table.
398 	 */
399 	for (i = 0; i < num_threads; i++) {
400 		thr_join(0, 0, 0);
401 	}
402 
403 	/*
404 	 * Need to only copy /var/statmon/sm.bak to alternate paths, since
405 	 * the only hosts in /var/statmon/sm should be the ones currently
406 	 * being monitored and already should be in alternate paths as part
407 	 * of insert_mon().
408 	 */
409 	for (i = 0; i < pathix; i++) {
410 		(void) sprintf(buf, "%s/statmon/sm.bak", path_name[i]);
411 		if ((mkdir(buf, SM_DIRECTORY_MODE)) == -1) {
412 			if (errno != EEXIST)
413 				syslog(LOG_ERR, "statd: mkdir %s error %m\n",
414 					buf);
415 			else
416 				copydir_from_to(BACKUP, buf);
417 		} else
418 			copydir_from_to(BACKUP, buf);
419 	}
420 
421 
422 	/*
423 	 * Reset the die and in_crash variable and signal other threads
424 	 * that have issued an sm_crash and are waiting.
425 	 */
426 	mutex_lock(&crash_lock);
427 	die = 0;
428 	in_crash = 0;
429 	mutex_unlock(&crash_lock);
430 	cond_broadcast(&crash_finish);
431 
432 	if (debug)
433 		(void) printf("Creating thread for sm_try\n");
434 
435 	/* Continue to notify statd on hosts that were unreachable. */
436 	if (thr_create(NULL, NULL, sm_try, NULL, THR_DETACHED, 0))
437 		syslog(LOG_ERR,
438 			"statd: unable to create thread for sm_try().\n");
439 	thr_exit((void *) 0);
440 #ifdef lint
441 	return (0);
442 #endif
443 }
444 
445 /*
446  * Work thread to make call to statd_call_statd.
447  */
448 void *
449 thr_call_statd(void *namep)
450 {
451 	char *name = (char *)namep;
452 
453 	/*
454 	 * If statd of name is unreachable, add name to recovery table
455 	 * otherwise if statd_call_statd was successful, remove from backup.
456 	 */
457 	if (statd_call_statd(name) != 0) {
458 		int n;
459 		char *tail;
460 		char path[MAXPATHLEN];
461 		/*
462 		 * since we are constructing this pathname below we add
463 		 *  another space for the terminating NULL so we don't
464 		 *  overflow our buffer when we do the readlink
465 		 */
466 		char rname[MAXNAMELEN + 1];
467 
468 		if (debug) {
469 			(void) printf(
470 			"statd call failed, inserting %s in recov_q\n", name);
471 		}
472 		mutex_lock(&recov_q.lock);
473 		(void) insert_name(&recov_q.sm_recovhdp, name, 0);
474 		mutex_unlock(&recov_q.lock);
475 
476 		/*
477 		 * If we queued a symlink name in the recovery queue,
478 		 * we now clean up the regular file to which it referred.
479 		 * This may leave a severed symlink if multiple links
480 		 * referred to one regular file; this is unaesthetic but
481 		 * it works.  The big benefit is that it prevents us
482 		 * from recovering the same host twice (as symlink and
483 		 * as regular file) needlessly, usually on separate reboots.
484 		 */
485 		(void) strcpy(path, BACKUP);
486 		(void) strcat(path, "/");
487 		(void) strcat(path, name);
488 		if (is_symlink(path)) {
489 			n = readlink(path, rname, MAXNAMELEN);
490 			if (n <= 0) {
491 				if (debug >= 2) {
492 					(void) printf(
493 					"thr_call_statd: can't read link %s\n",
494 							path);
495 				}
496 			} else {
497 				rname[n] = '\0';
498 
499 				tail = strrchr(path, '/') + 1;
500 
501 				if ((strlen(BACKUP) + strlen(rname) + 2) <=
502 				    MAXPATHLEN) {
503 					(void) strcpy(tail, rname);
504 					delete_file(path);
505 				} else if (debug) {
506 					printf("thr_call_statd: path over"
507 					    "maxpathlen!\n");
508 				}
509 			}
510 
511 		}
512 
513 		if (debug)
514 			pr_name(name, 0);
515 
516 	} else {
517 		/*
518 		 * If `name' is an IP address symlink to a name file,
519 		 * remove it now.  If it is the last such symlink,
520 		 * remove the name file as well.  Regular files with
521 		 * no symlinks to them are assumed to be legacies and
522 		 * are removed as well.
523 		 */
524 		remove_name(name, 1, 1);
525 		free(name);
526 	}
527 	thr_exit((void *) 0);
528 #ifdef lint
529 	return (0);
530 #endif
531 }
532 
533 /*
534  * Notifies the statd of host specified by name to indicate that
535  * state has changed for this server.
536  */
537 static int
538 statd_call_statd(name)
539 	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,
586 	    &tottimeout)) == (CLIENT *) 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 	/* For HA systems and multi-homed hosts */
606 	ntf.state = LOCAL_STATE;
607 	for (i = 0; i < addrix; i++) {
608 		ntf.mon_name = host_name[i];
609 		if (debug)
610 			(void) printf("statd_call_statd at %s\n", name_or_addr);
611 		clnt_stat = clnt_call(clnt, SM_NOTIFY, xdr_stat_chge,
612 					(char *)&ntf, xdr_void, NULL,
613 					tottimeout);
614 		if (clnt_stat != (int)RPC_SUCCESS) {
615 			syslog(LOG_WARNING,
616 			    "statd: cannot talk to statd at %s, %s(%d)\n",
617 			    name_or_addr, clnt_sperrno(clnt_stat), clnt_stat);
618 			rc = -1;
619 		}
620 	}
621 	clnt_destroy(clnt);
622 	return (rc);
623 }
624 
625 /*
626  * Continues to contact hosts in recovery table that were unreachable.
627  * NOTE:  There should only be one sm_try thread executing and
628  * thus locks are not needed for recovery table. Die is only cleared
629  * after all the hosts has at least been contacted once.  The reader/writer
630  * lock ensures to finish this code before an sm_crash is started.  Die
631  * variable will signal it.
632  */
633 void *
634 sm_try()
635 {
636 	name_entry *nl, *next;
637 	timestruc_t	wtime;
638 	int delay = 0;
639 
640 	rw_rdlock(&thr_rwlock);
641 	if (mutex_trylock(&sm_trylock))
642 		goto out;
643 	mutex_lock(&crash_lock);
644 
645 	while (!die) {
646 		wtime.tv_sec = delay;
647 		wtime.tv_nsec = 0;
648 		/*
649 		 * Wait until signalled to wakeup or time expired.
650 		 * If signalled to be awoken, then a crash has occurred
651 		 * or otherwise time expired.
652 		 */
653 		if (cond_reltimedwait(&retrywait, &crash_lock, &wtime) == 0) {
654 			break;
655 		}
656 
657 		/* Exit loop if queue is empty */
658 		if ((next = recov_q.sm_recovhdp) == NULL)
659 			break;
660 
661 		mutex_unlock(&crash_lock);
662 
663 		while (((nl = next) != (name_entry *)NULL) && (!die)) {
664 			next = next->nxt;
665 			if (statd_call_statd(nl->name) == 0) {
666 				/* remove name from BACKUP */
667 				remove_name(nl->name, 1, 0);
668 				mutex_lock(&recov_q.lock);
669 				/* remove entry from recovery_q */
670 				delete_name(&recov_q.sm_recovhdp, nl->name);
671 				mutex_unlock(&recov_q.lock);
672 			} else {
673 				/*
674 				 * Print message only once since unreachable
675 				 * host can be contacted forever.
676 				 */
677 				if (delay == 0)
678 					syslog(LOG_WARNING,
679 					"statd: host %s is not responding\n",
680 						nl->name);
681 			}
682 		}
683 		/*
684 		 * Increment the amount of delay before restarting again.
685 		 * The amount of delay should not exceed the MAX_DELAYTIME.
686 		 */
687 		if (delay <= MAX_DELAYTIME)
688 			delay += INC_DELAYTIME;
689 		mutex_lock(&crash_lock);
690 	}
691 
692 	mutex_unlock(&crash_lock);
693 	mutex_unlock(&sm_trylock);
694 out:
695 	rw_unlock(&thr_rwlock);
696 	if (debug)
697 		(void) printf("EXITING sm_try\n");
698 	thr_exit((void *) 0);
699 #ifdef lint
700 	return (0);
701 #endif
702 }
703 
704 /*
705  * Malloc's space and returns the ptr to malloc'ed space. NULL if unsuccessful.
706  */
707 char *
708 xmalloc(len)
709 	unsigned len;
710 {
711 	char *new;
712 
713 	if ((new = malloc(len)) == 0) {
714 		syslog(LOG_ERR, "statd: malloc, error %m\n");
715 		return ((char *)NULL);
716 	} else {
717 		(void) memset(new, 0, len);
718 		return (new);
719 	}
720 }
721 
722 /*
723  * the following two routines are very similar to
724  * insert_mon and delete_mon in sm_proc.c, except the structture
725  * is different
726  */
727 static name_entry *
728 insert_name(namepp, name, need_alloc)
729 	name_entry **namepp;
730 	char *name;
731 	int need_alloc;
732 {
733 	name_entry *new;
734 
735 	new = (name_entry *)xmalloc(sizeof (name_entry));
736 	if (new == (name_entry *) NULL)
737 		return (NULL);
738 
739 	/* Allocate name when needed which is only when adding to record_t */
740 	if (need_alloc) {
741 		if ((new->name = strdup(name)) == (char *)NULL) {
742 			syslog(LOG_ERR, "statd: strdup, error %m\n");
743 			free(new);
744 			return (NULL);
745 		}
746 	} else
747 		new->name = name;
748 
749 	new->nxt = *namepp;
750 	if (new->nxt != (name_entry *)NULL)
751 		new->nxt->prev = new;
752 
753 	new->prev = (name_entry *) NULL;
754 
755 	*namepp = new;
756 	if (debug) {
757 		(void) printf("insert_name: inserted %s at %p\n",
758 				name, (void *)namepp);
759 	}
760 
761 	return (new);
762 }
763 
764 /*
765  * Deletes name from specified list (namepp).
766  */
767 static void
768 delete_name(namepp, name)
769 	name_entry **namepp;
770 	char *name;
771 {
772 	name_entry *nl;
773 
774 	nl = *namepp;
775 	while (nl != (name_entry *)NULL) {
776 		if (str_cmp_address_specifier(nl->name, name) == 0 ||
777 		    str_cmp_unqual_hostname(nl->name, name) == 0) {
778 			if (nl->prev != (name_entry *)NULL)
779 				nl->prev->nxt = nl->nxt;
780 			else
781 				*namepp = nl->nxt;
782 			if (nl->nxt != (name_entry *)NULL)
783 				nl->nxt->prev = nl->prev;
784 			free(nl->name);
785 			free(nl);
786 			return;
787 		}
788 		nl = nl->nxt;
789 	}
790 }
791 
792 /*
793  * Finds name from specified list (namep).
794  */
795 static name_entry *
796 find_name(namep, name)
797 	name_entry **namep;
798 	char *name;
799 {
800 	name_entry *nl;
801 
802 	nl = *namep;
803 
804 	while (nl != (name_entry *)NULL) {
805 		if (str_cmp_unqual_hostname(nl->name, name) == 0) {
806 			return (nl);
807 		}
808 		nl = nl->nxt;
809 	}
810 	return ((name_entry *)NULL);
811 }
812 
813 /*
814  * Creates a file.
815  */
816 
817 int
818 create_file(name)
819 	char *name;
820 {
821 	int fd;
822 
823 	/*
824 	 * The file might already exist.  If it does, we ask for only write
825 	 * permission, since that's all the file was created with.
826 	 */
827 	if ((fd = open(name, O_CREAT | O_WRONLY, S_IWUSR)) == -1) {
828 		if (errno != EEXIST) {
829 			syslog(LOG_ERR, "can't open %s: %m", name);
830 			return (1);
831 		}
832 	}
833 
834 	if (debug >= 2)
835 		(void) printf("%s is created\n", name);
836 	if (close(fd)) {
837 		syslog(LOG_ERR, "statd: close, error %m\n");
838 		return (1);
839 	}
840 
841 	return (0);
842 }
843 
844 /*
845  * Deletes the file specified by name.
846  */
847 void
848 delete_file(name)
849 	char *name;
850 {
851 	if (debug >= 2)
852 		(void) printf("Remove monitor entry %s\n", name);
853 	if (unlink(name) == -1) {
854 		if (errno != ENOENT)
855 			syslog(LOG_ERR, "statd: unlink of %s, error %m", name);
856 	}
857 }
858 
859 /*
860  * Return 1 if file is a symlink, else 0.
861  */
862 int
863 is_symlink(file)
864 	char *file;
865 {
866 	int error;
867 	struct stat lbuf;
868 
869 	do {
870 		bzero((caddr_t)&lbuf, sizeof (lbuf));
871 		error = lstat(file, &lbuf);
872 	} while (error == EINTR);
873 
874 	if (error == 0) {
875 		return ((lbuf.st_mode & S_IFMT) == S_IFLNK);
876 	}
877 
878 	return (0);
879 }
880 
881 /*
882  * Moves the file specified by `from' to `to' only if the
883  * new file is guaranteed to be created (which is presumably
884  * why we don't just do a rename(2)).  If `from' is a
885  * symlink, the destination file will be a similar symlink
886  * in the directory of `to'.
887  *
888  * Returns 0 for success, 1 for failure.
889  */
890 static int
891 move_file(fromdir, file, todir)
892 	char *fromdir;
893 	char *file;
894 	char *todir;
895 {
896 	int n;
897 	char rname[MAXNAMELEN + 1]; /* +1 for the terminating NULL */
898 	char from[MAXPATHLEN];
899 	char to[MAXPATHLEN];
900 
901 	(void) strcpy(from, fromdir);
902 	(void) strcat(from, "/");
903 	(void) strcat(from, file);
904 	if (is_symlink(from)) {
905 		/*
906 		 * Dig out the name of the regular file the link points to.
907 		 */
908 		n = readlink(from, rname, MAXNAMELEN);
909 		if (n <= 0) {
910 			if (debug >= 2) {
911 				(void) printf("move_file: can't read link %s\n",
912 						from);
913 			}
914 			return (1);
915 		}
916 		rname[n] = '\0';
917 
918 		/*
919 		 * Create the link.
920 		 */
921 		if (create_symlink(todir, rname, file) != 0) {
922 			return (1);
923 		}
924 	} else {
925 		/*
926 		 * Do what we've always done to move regular files.
927 		 */
928 		(void) strcpy(to, todir);
929 		(void) strcat(to, "/");
930 		(void) strcat(to, file);
931 		if (create_file(to) != 0) {
932 			return (1);
933 		}
934 	}
935 
936 	/*
937 	 * Remove the old file if we've created the new one.
938 	 */
939 	if (unlink(from) < 0) {
940 		syslog(LOG_ERR, "move_file: unlink of %s, error %m", from);
941 		return (1);
942 	}
943 
944 	return (0);
945 }
946 
947 /*
948  * Create a symbolic link named `lname' to regular file `rname'.
949  * Both files should be in directory `todir'.
950  */
951 int
952 create_symlink(todir, rname, lname)
953 	char *todir;
954 	char *rname;
955 	char *lname;
956 {
957 	int error;
958 	char lpath[MAXPATHLEN];
959 
960 	/*
961 	 * Form the full pathname of the link.
962 	 */
963 	(void) strcpy(lpath, todir);
964 	(void) strcat(lpath, "/");
965 	(void) strcat(lpath, lname);
966 
967 	/*
968 	 * Now make the new symlink ...
969 	 */
970 	if (symlink(rname, lpath) < 0) {
971 		error = errno;
972 		if (error != 0 && error != EEXIST) {
973 			if (debug >= 2) {
974 				(void) printf(
975 				"create_symlink: can't link %s/%s -> %s\n",
976 					todir, lname, rname);
977 			}
978 			return (1);
979 		}
980 	}
981 
982 	if (debug) {
983 		if (error == EEXIST) {
984 			(void) printf("link %s/%s -> %s already exists\n",
985 				todir, lname, rname);
986 		} else {
987 			(void) printf("created link %s/%s -> %s\n",
988 				todir, lname, rname);
989 		}
990 	}
991 
992 	return (0);
993 }
994 
995 /*
996  * remove the name from the specified directory
997  * op = 0: CURRENT
998  * op = 1: BACKUP
999  */
1000 static void
1001 remove_name(char *name, int op, int startup)
1002 {
1003 	int i;
1004 	char *alt_dir;
1005 	char *queue;
1006 
1007 	if (op == 0) {
1008 		alt_dir = "statmon/sm";
1009 		queue = CURRENT;
1010 	} else {
1011 		alt_dir = "statmon/sm.bak";
1012 		queue = BACKUP;
1013 	}
1014 
1015 	remove_single_name(name, queue, NULL);
1016 	/*
1017 	 * At startup, entries have not yet been copied to alternate
1018 	 * directories and thus do not need to be removed.
1019 	 */
1020 	if (startup == 0) {
1021 		for (i = 0; i < pathix; i++) {
1022 			remove_single_name(name, path_name[i], alt_dir);
1023 		}
1024 	}
1025 }
1026 
1027 /*
1028  * Remove the name from the specified directory, which is dir1/dir2 or
1029  * dir1, depending on whether dir2 is NULL.
1030  */
1031 static void
1032 remove_single_name(char *name, char *dir1, char *dir2)
1033 {
1034 	int n, error;
1035 	char path[MAXPATHLEN+MAXNAMELEN+SM_MAXPATHLEN];	/* why > MAXPATHLEN? */
1036 	char dirpath[MAXPATHLEN];
1037 	char rname[MAXNAMELEN + 1]; /* +1 for NULL term */
1038 
1039 	if (strlen(name) + strlen(dir1) + (dir2 != NULL ? strlen(dir2) : 0)
1040 			+ 3 > MAXPATHLEN) {
1041 		if (dir2 != NULL)
1042 			syslog(LOG_ERR,
1043 				"statd: pathname too long: %s/%s/%s\n",
1044 						dir1, dir2, name);
1045 		else
1046 			syslog(LOG_ERR,
1047 				"statd: pathname too long: %s/%s\n",
1048 						dir1, name);
1049 
1050 		return;
1051 	}
1052 
1053 	(void) strcpy(path, dir1);
1054 	(void) strcat(path, "/");
1055 	if (dir2 != NULL) {
1056 		(void) strcat(path, dir2);
1057 		(void) strcat(path, "/");
1058 	}
1059 	(void) strcpy(dirpath, path);	/* save here - we may need it shortly */
1060 	(void) strcat(path, name);
1061 
1062 	/*
1063 	 * Despite the name of this routine :-@), `path' may be a symlink
1064 	 * to a regular file.  If it is, and if that file has no other
1065 	 * links to it, we must remove it now as well.
1066 	 */
1067 	if (is_symlink(path)) {
1068 		n = readlink(path, rname, MAXNAMELEN);
1069 		if (n > 0) {
1070 			rname[n] = '\0';
1071 
1072 			if (count_symlinks(dirpath, rname, &n) < 0) {
1073 				return;
1074 			}
1075 
1076 			if (n == 1) {
1077 				(void) strcat(dirpath, rname);
1078 				error = unlink(dirpath);
1079 				if (debug >= 2) {
1080 					if (error < 0) {
1081 						(void) printf(
1082 					"remove_name: can't unlink %s\n",
1083 							dirpath);
1084 					} else {
1085 						(void) printf(
1086 					"remove_name: unlinked %s\n",
1087 							dirpath);
1088 					}
1089 				}
1090 			}
1091 		} else {
1092 			/*
1093 			 * Policy: if we can't read the symlink, leave it
1094 			 * here for analysis by the system administrator.
1095 			 */
1096 			syslog(LOG_ERR,
1097 				"statd: can't read link %s: %m\n", path);
1098 		}
1099 	}
1100 
1101 	/*
1102 	 * If it's a regular file, we can assume all symlinks and the
1103 	 * files to which they refer have been processed already - just
1104 	 * fall through to here to remove it.
1105 	 */
1106 	delete_file(path);
1107 }
1108 
1109 /*
1110  * Count the number of symlinks in `dir' which point to `name' (also in dir).
1111  * Passes back symlink count in `count'.
1112  * Returns 0 for success, < 0 for failure.
1113  */
1114 static int
1115 count_symlinks(char *dir, char *name, int *count)
1116 {
1117 	int cnt = 0;
1118 	int n;
1119 	DIR *dp;
1120 	struct dirent *dirp;
1121 	char lpath[MAXPATHLEN];
1122 	char rname[MAXNAMELEN + 1]; /* +1 for term NULL */
1123 
1124 	if ((dp = opendir(dir)) == (DIR *)NULL) {
1125 		syslog(LOG_ERR, "count_symlinks: open %s dir, error %m\n",
1126 			dir);
1127 		return (-1);
1128 	}
1129 
1130 	while ((dirp = readdir(dp)) != NULL) {
1131 		if (strcmp(dirp->d_name, ".") == 0 ||
1132 			strcmp(dirp->d_name, "..") == 0) {
1133 			continue;
1134 		}
1135 
1136 		(void) sprintf(lpath, "%s%s", dir, dirp->d_name);
1137 		if (is_symlink(lpath)) {
1138 			/*
1139 			 * Fetch the name of the file the symlink refers to.
1140 			 */
1141 			n = readlink(lpath, rname, MAXNAMELEN);
1142 			if (n <= 0) {
1143 				if (debug >= 2) {
1144 					(void) printf(
1145 					"count_symlinks: can't read link %s\n",
1146 						lpath);
1147 				}
1148 				continue;
1149 			}
1150 			rname[n] = '\0';
1151 
1152 			/*
1153 			 * If `rname' matches `name', bump the count.  There
1154 			 * may well be multiple symlinks to the same name, so
1155 			 * we must continue to process the entire directory.
1156 			 */
1157 			if (strcmp(rname, name) == 0) {
1158 				cnt++;
1159 			}
1160 		}
1161 	}
1162 
1163 	(void) closedir(dp);
1164 
1165 	if (debug) {
1166 		(void) printf("count_symlinks: found %d symlinks\n", cnt);
1167 	}
1168 	*count = cnt;
1169 	return (0);
1170 }
1171 
1172 /*
1173  * Manage the cache of hostnames.  An entry for each host that has recently
1174  * locked a file is kept.  There is an in-ram table (rec_table) and an empty
1175  * file in the file system name space (/var/statmon/sm/<name>).  This
1176  * routine adds (deletes) the name to (from) the in-ram table and the entry
1177  * to (from) the file system name space.
1178  *
1179  * If op == 1 then the name is added to the queue otherwise the name is
1180  * deleted.
1181  */
1182 void
1183 record_name(name, op)
1184 	char *name;
1185 	int op;
1186 {
1187 	name_entry *nl;
1188 	int i;
1189 	char path[MAXPATHLEN+MAXNAMELEN+SM_MAXPATHLEN];
1190 	name_entry **record_q;
1191 	unsigned int hash;
1192 
1193 	/*
1194 	 * These names are supposed to be just host names, not paths or
1195 	 * other arbitrary files.
1196 	 * manipulating the empty pathname unlinks CURRENT,
1197 	 * manipulating files with '/' would allow you to create and unlink
1198 	 * files all over the system; LOG_AUTH, it's a security thing.
1199 	 * Don't remove the directories . and ..
1200 	 */
1201 	if (name == NULL)
1202 		return;
1203 
1204 	if (name[0] == '\0' || strchr(name, '/') != NULL ||
1205 			strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
1206 		syslog(LOG_ERR|LOG_AUTH, "statd: attempt to %s \"%s/%s\"",
1207 			op == 1 ? "create" : "remove", CURRENT, name);
1208 		return;
1209 	}
1210 
1211 	SMHASH(name, hash);
1212 	if (debug) {
1213 		if (op == 1)
1214 			(void) printf("inserting %s at hash %d,\n",
1215 			name, hash);
1216 		else
1217 			(void) printf("deleting %s at hash %d\n", name, hash);
1218 		pr_name(name, 1);
1219 	}
1220 
1221 
1222 	if (op == 1) { /* insert */
1223 		mutex_lock(&record_table[hash].lock);
1224 		record_q = &record_table[hash].sm_rechdp;
1225 		if ((nl = find_name(record_q, name)) == (name_entry *)NULL) {
1226 
1227 			int	path_len;
1228 
1229 			if ((nl = insert_name(record_q, name, 1)) !=
1230 			    (name_entry *) NULL)
1231 				nl->count++;
1232 			mutex_unlock(&record_table[hash].lock);
1233 			/* make an entry in current directory */
1234 
1235 			path_len = strlen(CURRENT) + strlen(name) + 2;
1236 			if (path_len > MAXPATHLEN) {
1237 				syslog(LOG_ERR,
1238 					"statd: pathname too long: %s/%s\n",
1239 						CURRENT, name);
1240 				return;
1241 			}
1242 			(void) strcpy(path, CURRENT);
1243 			(void) strcat(path, "/");
1244 			(void) strcat(path, name);
1245 			(void) create_file(path);
1246 			if (debug) {
1247 				(void) printf("After insert_name\n");
1248 				pr_name(name, 1);
1249 			}
1250 			/* make an entry in alternate paths */
1251 			for (i = 0; i < pathix; i++) {
1252 				path_len = strlen(path_name[i]) +
1253 							strlen("/statmon/sm/") +
1254 							strlen(name) + 1;
1255 
1256 				if (path_len > MAXPATHLEN) {
1257 					syslog(LOG_ERR,
1258 				"statd: pathname too long: %s/statmon/sm/%s\n",
1259 							path_name[i], name);
1260 					continue;
1261 				}
1262 				(void) strcpy(path, path_name[i]);
1263 				(void) strcat(path, "/statmon/sm/");
1264 				(void) strcat(path, name);
1265 				(void) create_file(path);
1266 			}
1267 			return;
1268 		}
1269 		nl->count++;
1270 		mutex_unlock(&record_table[hash].lock);
1271 
1272 	} else { /* delete */
1273 		mutex_lock(&record_table[hash].lock);
1274 		record_q = &record_table[hash].sm_rechdp;
1275 		if ((nl = find_name(record_q, name)) == (name_entry *)NULL) {
1276 			mutex_unlock(&record_table[hash].lock);
1277 			return;
1278 		}
1279 		nl->count--;
1280 		if (nl->count == 0) {
1281 			delete_name(record_q, name);
1282 			mutex_unlock(&record_table[hash].lock);
1283 			/* remove this entry from current directory */
1284 			remove_name(name, 0, 0);
1285 		} else
1286 			mutex_unlock(&record_table[hash].lock);
1287 		if (debug) {
1288 			(void) printf("After delete_name \n");
1289 			pr_name(name, 1);
1290 		}
1291 	}
1292 }
1293 
1294 /*
1295  * This routine adds a symlink in the form of an ASCII dotted quad
1296  * IP address that is linked to the name already recorded in the
1297  * filesystem name space by record_name().  Enough information is
1298  * (hopefully) provided to support other address types in the future.
1299  * The purpose of this is to cache enough information to contact
1300  * hosts in other domains during server crash recovery (see bugid
1301  * 1184192).
1302  *
1303  * The worst failure mode here is that the symlink is not made, and
1304  * statd falls back to the old buggy behavior.
1305  */
1306 void
1307 record_addr(char *name, sa_family_t family, struct netobj *ah)
1308 {
1309 	int i;
1310 	int path_len;
1311 	char *famstr;
1312 	struct in_addr addr;
1313 	char *addr6;
1314 	char ascii_addr[MAXNAMELEN];
1315 	char path[MAXPATHLEN];
1316 
1317 	if (family == AF_INET) {
1318 		if (ah->n_len != sizeof (struct in_addr))
1319 			return;
1320 		addr = *(struct in_addr *)ah->n_bytes;
1321 	} else if (family == AF_INET6) {
1322 			if (ah->n_len != sizeof (struct in6_addr))
1323 				return;
1324 			addr6 = (char *)ah->n_bytes;
1325 	} else
1326 		return;
1327 
1328 	if (debug) {
1329 		if (family == AF_INET)
1330 			(void) printf("record_addr: addr= %x\n", addr.s_addr);
1331 		else if (family == AF_INET6)
1332 			(void) printf("record_addr: addr= %x\n", \
1333 				((struct in6_addr *)addr6)->s6_addr);
1334 	}
1335 
1336 	if (family == AF_INET) {
1337 		if (addr.s_addr == INADDR_ANY ||
1338 		    ((addr.s_addr && 0xff000000) == 0) ||
1339 		    IN_BADCLASS(addr.s_addr)) {
1340 			syslog(LOG_DEBUG,
1341 				"record_addr: illegal IP address %x\n",
1342 				addr.s_addr);
1343 			return;
1344 		}
1345 	}
1346 
1347 	/* convert address to ASCII */
1348 	famstr = family2string(family);
1349 	if (famstr == NULL) {
1350 		syslog(LOG_DEBUG,
1351 			"record_addr: unsupported address family %d\n",
1352 			family);
1353 		return;
1354 	}
1355 
1356 	switch (family) {
1357 		char abuf[INET6_ADDRSTRLEN];
1358 	    case AF_INET:
1359 		(void) sprintf(ascii_addr, "%s.%s", famstr, inet_ntoa(addr));
1360 		break;
1361 
1362 	    case AF_INET6:
1363 		(void) sprintf(ascii_addr, "%s.%s", famstr,\
1364 		    inet_ntop(family, addr6, abuf, sizeof (abuf)));
1365 		break;
1366 
1367 	    default:
1368 		if (debug) {
1369 			(void) printf(
1370 		"record_addr: family2string supports unknown family %d (%s)\n",
1371 				family,
1372 				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