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