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