xref: /illumos-gate/usr/src/cmd/fs.d/nfs/statd/sm_proc.c (revision b17f03d7)
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 2013 Nexenta Systems, Inc.  All rights reserved.
28  */
29 
30 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
31 /*	  All Rights Reserved  	*/
32 
33 /*
34  * University Copyright- Copyright (c) 1982, 1986, 1988
35  * The Regents of the University of California
36  * All Rights Reserved
37  *
38  * University Acknowledgment- Portions of this document are derived from
39  * software developed by the University of California, Berkeley, and its
40  * contributors.
41  */
42 
43 #include <stdio.h>
44 #include <sys/types.h>
45 #include <stdlib.h>
46 #include <unistd.h>
47 #include <string.h>
48 #include <syslog.h>
49 #include <rpc/rpc.h>
50 #include <rpcsvc/sm_inter.h>
51 #include <rpcsvc/nsm_addr.h>
52 #include <memory.h>
53 #include <net/if.h>
54 #include <sys/sockio.h>
55 #include <sys/socket.h>
56 #include <netinet/in.h>
57 #include <arpa/inet.h>
58 #include <netdb.h>
59 #include <netdir.h>
60 #include <synch.h>
61 #include <thread.h>
62 #include <assert.h>
63 #include "sm_statd.h"
64 
65 static int local_state;		/* fake local sm state */
66 				/* client name-to-address translation table */
67 static name_addr_entry_t *name_addr = NULL;
68 
69 
70 #define	LOGHOST "loghost"
71 
72 static void delete_mon(char *mon_name, my_id *my_idp);
73 static void insert_mon(mon *monp);
74 static void pr_mon(char *);
75 static int statd_call_lockd(mon *monp, int state);
76 static int hostname_eq(char *host1, char *host2);
77 static char *get_system_id(char *hostname);
78 static void add_aliases(struct hostent *phost);
79 static void *thr_send_notice(void *);
80 static void delete_onemon(char *mon_name, my_id *my_idp,
81 				mon_entry **monitor_q);
82 static void send_notice(char *mon_name, int state);
83 static void add_to_host_array(char *host);
84 static int in_host_array(char *host);
85 static void pr_name_addr(name_addr_entry_t *name_addr);
86 
87 extern int self_check(char *hostname);
88 extern struct lifconf *getmyaddrs(void);
89 
90 /* ARGSUSED */
91 void
92 sm_status(namep, resp)
93 	sm_name *namep;
94 	sm_stat_res *resp;
95 {
96 
97 	if (debug)
98 		(void) printf("proc sm_stat: mon_name = %s\n",
99 				namep->mon_name);
100 
101 	resp->res_stat = stat_succ;
102 	resp->state = LOCAL_STATE;
103 }
104 
105 /* ARGSUSED */
106 void
107 sm_mon(monp, resp)
108 	mon *monp;
109 	sm_stat_res *resp;
110 {
111 	mon_id *monidp;
112 	monidp = &monp->mon_id;
113 
114 	rw_rdlock(&thr_rwlock);
115 	if (debug) {
116 		(void) printf("proc sm_mon: mon_name = %s, id = %d\n",
117 		monidp->mon_name, * ((int *)monp->priv));
118 		pr_mon(monp->mon_id.mon_name);
119 	}
120 
121 	/* only monitor other hosts */
122 	if (self_check(monp->mon_id.mon_name) == 0) {
123 		/* store monitor request into monitor_q */
124 		insert_mon(monp);
125 	}
126 
127 	pr_mon(monp->mon_id.mon_name);
128 	resp->res_stat = stat_succ;
129 	resp->state = local_state;
130 	rw_unlock(&thr_rwlock);
131 }
132 
133 /* ARGSUSED */
134 void
135 sm_unmon(monidp, resp)
136 	mon_id *monidp;
137 	sm_stat *resp;
138 {
139 	rw_rdlock(&thr_rwlock);
140 	if (debug) {
141 		(void) printf(
142 			"proc sm_unmon: mon_name = %s, [%s, %d, %d, %d]\n",
143 			monidp->mon_name, monidp->my_id.my_name,
144 			monidp->my_id.my_prog, monidp->my_id.my_vers,
145 			monidp->my_id.my_proc);
146 		pr_mon(monidp->mon_name);
147 	}
148 
149 	delete_mon(monidp->mon_name, &monidp->my_id);
150 	pr_mon(monidp->mon_name);
151 	resp->state = local_state;
152 	rw_unlock(&thr_rwlock);
153 }
154 
155 /* ARGSUSED */
156 void
157 sm_unmon_all(myidp, resp)
158 	my_id *myidp;
159 	sm_stat *resp;
160 {
161 	rw_rdlock(&thr_rwlock);
162 	if (debug)
163 		(void) printf("proc sm_unmon_all: [%s, %d, %d, %d]\n",
164 		myidp->my_name,
165 		myidp->my_prog, myidp->my_vers,
166 		myidp->my_proc);
167 	delete_mon((char *)NULL, myidp);
168 	pr_mon(NULL);
169 	resp->state = local_state;
170 	rw_unlock(&thr_rwlock);
171 }
172 
173 /*
174  * Notifies lockd specified by name that state has changed for this server.
175  */
176 void
177 sm_notify(ntfp)
178 	stat_chge *ntfp;
179 {
180 	rw_rdlock(&thr_rwlock);
181 	if (debug)
182 		(void) printf("sm_notify: %s state =%d\n",
183 			ntfp->mon_name, ntfp->state);
184 	send_notice(ntfp->mon_name, ntfp->state);
185 	rw_unlock(&thr_rwlock);
186 }
187 
188 /* ARGSUSED */
189 void
190 sm_simu_crash(myidp)
191 	void *myidp;
192 {
193 	int i;
194 	struct mon_entry *monitor_q;
195 	int found = 0;
196 
197 	/* Only one crash should be running at a time. */
198 	mutex_lock(&crash_lock);
199 	if (debug)
200 		(void) printf("proc sm_simu_crash\n");
201 	if (in_crash) {
202 		cond_wait(&crash_finish, &crash_lock);
203 		mutex_unlock(&crash_lock);
204 		return;
205 	} else {
206 		in_crash = 1;
207 	}
208 	mutex_unlock(&crash_lock);
209 
210 	for (i = 0; i < MAX_HASHSIZE; i++) {
211 		mutex_lock(&mon_table[i].lock);
212 		monitor_q = mon_table[i].sm_monhdp;
213 		if (monitor_q != (struct mon_entry *)NULL) {
214 			mutex_unlock(&mon_table[i].lock);
215 			found = 1;
216 			break;
217 		}
218 		mutex_unlock(&mon_table[i].lock);
219 	}
220 	/*
221 	 * If there are entries found in the monitor table,
222 	 * initiate a crash, else zero out the in_crash variable.
223 	 */
224 	if (found) {
225 		mutex_lock(&crash_lock);
226 		die = 1;
227 		/* Signal sm_retry() thread if sleeping. */
228 		cond_signal(&retrywait);
229 		mutex_unlock(&crash_lock);
230 		rw_wrlock(&thr_rwlock);
231 		sm_crash();
232 		rw_unlock(&thr_rwlock);
233 	} else {
234 		mutex_lock(&crash_lock);
235 		in_crash = 0;
236 		mutex_unlock(&crash_lock);
237 	}
238 }
239 
240 /* ARGSUSED */
241 void
242 nsmaddrproc1_reg(regargs, regresp)
243 	reg1args *regargs;
244 	reg1res  *regresp;
245 {
246 	nsm_addr_res status;
247 	name_addr_entry_t *entry;
248 	char *tmp_n_bytes;
249 	addr_entry_t *addr;
250 
251 	rw_rdlock(&thr_rwlock);
252 	if (debug) {
253 		int i;
254 
255 		(void) printf("nap1_reg: fam= %d, name= %s, len= %d\n",
256 				regargs->family,
257 				regargs->name,
258 				regargs->address.n_len);
259 		(void) printf("address is: ");
260 		for (i = 0; i < regargs->address.n_len; i++) {
261 			(void) printf("%d.",
262 				(unsigned char)regargs->address.n_bytes[i]);
263 		}
264 		(void) printf("\n");
265 	}
266 
267 	/*
268 	 * Locate the entry with the name in the NSM_ADDR_REG request if
269 	 * it exists.  If it doesn't, create a new entry to hold this name.
270 	 * The first time through this code, name_addr starts out as NULL.
271 	 */
272 	mutex_lock(&name_addrlock);
273 	for (entry = name_addr; entry; entry = entry->next) {
274 		if (strcmp(regargs->name, entry->name) == 0) {
275 			if (debug) {
276 				(void) printf("nap1_reg: matched name %s\n",
277 						entry->name);
278 			}
279 			break;
280 		}
281 	}
282 
283 	if (entry == NULL) {
284 		entry = (name_addr_entry_t *)malloc(sizeof (*entry));
285 		if (entry == NULL) {
286 			if (debug) {
287 				(void) printf(
288 				"nsmaddrproc1_reg: no memory for entry\n");
289 			}
290 			status = nsm_addr_fail;
291 			goto done;
292 		}
293 
294 		entry->name = strdup(regargs->name);
295 		if (entry->name == NULL) {
296 			if (debug) {
297 				(void) printf(
298 				"nsmaddrproc1_reg: no memory for name\n");
299 			}
300 			free(entry);
301 			status = nsm_addr_fail;
302 			goto done;
303 		}
304 		entry->addresses = NULL;
305 
306 		/*
307 		 * Link the new entry onto the *head* of the name_addr
308 		 * table.
309 		 *
310 		 * Note: there is code below in the address maintenance
311 		 * section that assumes this behavior.
312 		 */
313 		entry->next = name_addr;
314 		name_addr = entry;
315 	}
316 
317 	/*
318 	 * Try to match the address in the request; if it doesn't match,
319 	 * add it to the entry's address list.
320 	 */
321 	for (addr = entry->addresses; addr; addr = addr->next) {
322 		if (addr->family == (sa_family_t)regargs->family &&
323 		    addr->ah.n_len == regargs->address.n_len &&
324 		    memcmp(addr->ah.n_bytes, regargs->address.n_bytes,
325 			addr->ah.n_len) == 0) {
326 			if (debug) {
327 				int i;
328 
329 				(void) printf("nap1_reg: matched addr ");
330 				for (i = 0; i < addr->ah.n_len; i++) {
331 					(void) printf("%d.",
332 					(unsigned char)addr->ah.n_bytes[i]);
333 				}
334 				(void) printf(" family %d for name %s\n",
335 						addr->family,
336 						entry->name);
337 			}
338 			break;
339 		}
340 	}
341 
342 	if (addr == NULL) {
343 		addr = (addr_entry_t *)malloc(sizeof (*addr));
344 		tmp_n_bytes = (char *)malloc(regargs->address.n_len);
345 		if (addr == NULL || tmp_n_bytes == NULL) {
346 			if (debug) {
347 				(void) printf(
348 					"nap1_reg: no memory for addr\n");
349 			}
350 
351 			/*
352 			 * If this name entry was just newly made in the
353 			 * table, back it out now that we can't register
354 			 * an address with it anyway.
355 			 *
356 			 * Note: we are making an assumption about how
357 			 * names are added to (the head of) name_addr here.
358 			 */
359 			if (entry == name_addr && entry->addresses == NULL) {
360 				name_addr = name_addr->next;
361 				free(entry->name);
362 				free(entry);
363 				if (tmp_n_bytes)
364 					free(tmp_n_bytes);
365 				if (addr)
366 					free(addr);
367 				status = nsm_addr_fail;
368 				goto done;
369 			}
370 		}
371 
372 		/*
373 		 * Note:  this check for address family assumes that we
374 		 *	  will get something different here someday for
375 		 *	  other supported address types, such as IPv6.
376 		 */
377 		addr->ah.n_len = regargs->address.n_len;
378 		addr->ah.n_bytes = tmp_n_bytes;
379 		addr->family = regargs->family;
380 		if (debug) {
381 			if ((addr->family != AF_INET) && \
382 				(addr->family != AF_INET6)) {
383 				(void) printf(
384 					"nap1_reg: unknown addr family %d\n",
385 					addr->family);
386 			}
387 		}
388 		(void) memcpy(addr->ah.n_bytes, regargs->address.n_bytes,
389 				addr->ah.n_len);
390 
391 		addr->next = entry->addresses;
392 		entry->addresses = addr;
393 	}
394 
395 	status = nsm_addr_succ;
396 
397 done:
398 	regresp->status = status;
399 	if (debug) {
400 		pr_name_addr(name_addr);
401 	}
402 	mutex_unlock(&name_addrlock);
403 	rw_unlock(&thr_rwlock);
404 }
405 
406 /*
407  * Insert an entry into the monitor_q.  Space for the entry is allocated
408  * here.  It is then filled in from the information passed in.
409  */
410 static void
411 insert_mon(monp)
412 	mon *monp;
413 {
414 	mon_entry *new, *found;
415 	my_id *my_idp, *nl_idp;
416 	mon_entry *monitor_q;
417 	unsigned int hash;
418 	name_addr_entry_t *entry;
419 	addr_entry_t *addr;
420 
421 	/* Allocate entry for new */
422 	if ((new = (mon_entry *) malloc(sizeof (mon_entry))) == 0) {
423 		syslog(LOG_ERR,
424 			"statd: insert_mon: malloc error on mon %s (id=%d)\n",
425 			monp->mon_id.mon_name, * ((int *)monp->priv));
426 		return;
427 	}
428 
429 	/* Initialize and copy contents of monp to new */
430 	(void) memset(new, 0, sizeof (mon_entry));
431 	(void) memcpy(&new->id, monp, sizeof (mon));
432 
433 	/* Allocate entry for new mon_name */
434 	if ((new->id.mon_id.mon_name = strdup(monp->mon_id.mon_name)) == 0) {
435 		syslog(LOG_ERR,
436 			"statd: insert_mon: malloc error on mon %s (id=%d)\n",
437 			monp->mon_id.mon_name, * ((int *)monp->priv));
438 		free(new);
439 		return;
440 	}
441 
442 
443 	/* Allocate entry for new my_name */
444 	if ((new->id.mon_id.my_id.my_name =
445 		strdup(monp->mon_id.my_id.my_name)) == 0) {
446 		syslog(LOG_ERR,
447 			"statd: insert_mon: malloc error on mon %s (id=%d)\n",
448 			monp->mon_id.mon_name, * ((int *)monp->priv));
449 		free(new->id.mon_id.mon_name);
450 		free(new);
451 		return;
452 	}
453 
454 	if (debug)
455 		(void) printf("add_mon(%x) %s (id=%d)\n",
456 		(int)new, new->id.mon_id.mon_name, * ((int *)new->id.priv));
457 
458 	/*
459 	 * Record the name, and all addresses which have been registered
460 	 * for this name, in the filesystem name space.
461 	 */
462 	record_name(new->id.mon_id.mon_name, 1);
463 	if (regfiles_only == 0) {
464 		mutex_lock(&name_addrlock);
465 		for (entry = name_addr; entry; entry = entry->next) {
466 			if (strcmp(new->id.mon_id.mon_name, entry->name) != 0) {
467 				continue;
468 			}
469 
470 			for (addr = entry->addresses; addr; addr = addr->next) {
471 				record_addr(new->id.mon_id.mon_name,
472 						addr->family, &addr->ah);
473 			}
474 			break;
475 		}
476 		mutex_unlock(&name_addrlock);
477 	}
478 
479 	SMHASH(new->id.mon_id.mon_name, hash);
480 	mutex_lock(&mon_table[hash].lock);
481 	monitor_q = mon_table[hash].sm_monhdp;
482 
483 	/* If mon_table hash list is empty. */
484 	if (monitor_q == (struct mon_entry *)NULL) {
485 		if (debug)
486 			(void) printf("\nAdding to monitor_q hash %d\n", hash);
487 		new->nxt = new->prev = (mon_entry *)NULL;
488 		mon_table[hash].sm_monhdp = new;
489 		mutex_unlock(&mon_table[hash].lock);
490 		return;
491 	} else {
492 		found = 0;
493 		my_idp = &new->id.mon_id.my_id;
494 		while (monitor_q != (mon_entry *)NULL)  {
495 			/*
496 			 * This list is searched sequentially for the
497 			 * tuple (hostname, prog, vers, proc). The tuples
498 			 * are inserted in the beginning of the monitor_q,
499 			 * if the hostname is not already present in the list.
500 			 * If the hostname is found in the list, the incoming
501 			 * tuple is inserted just after all the tuples with the
502 			 * same hostname. However, if the tuple matches exactly
503 			 * with an entry in the list, space allocated for the
504 			 * new entry is released and nothing is inserted in the
505 			 * list.
506 			 */
507 
508 			if (str_cmp_unqual_hostname(
509 				monitor_q->id.mon_id.mon_name,
510 				new->id.mon_id.mon_name) == 0) {
511 				/* found */
512 				nl_idp = &monitor_q->id.mon_id.my_id;
513 				if ((str_cmp_unqual_hostname(my_idp->my_name,
514 					nl_idp->my_name) == 0) &&
515 					my_idp->my_prog == nl_idp->my_prog &&
516 					my_idp->my_vers == nl_idp->my_vers &&
517 					my_idp->my_proc == nl_idp->my_proc) {
518 					/*
519 					 * already exists an identical one,
520 					 * release the space allocated for the
521 					 * mon_entry
522 					 */
523 					free(new->id.mon_id.mon_name);
524 					free(new->id.mon_id.my_id.my_name);
525 					free(new);
526 					mutex_unlock(&mon_table[hash].lock);
527 					return;
528 				} else {
529 					/*
530 					 * mark the last callback that is
531 					 * not matching; new is inserted
532 					 * after this
533 					 */
534 					found = monitor_q;
535 				}
536 			} else if (found)
537 				break;
538 			monitor_q = monitor_q->nxt;
539 		}
540 		if (found) {
541 			/*
542 			 * insert just after the entry having matching tuple.
543 			 */
544 			new->nxt = found->nxt;
545 			new->prev = found;
546 			if (found->nxt != (mon_entry *)NULL)
547 				found->nxt->prev = new;
548 			found->nxt = new;
549 		} else {
550 			/*
551 			 * not found, insert in front of list.
552 			 */
553 			new->nxt = mon_table[hash].sm_monhdp;
554 			new->prev = (mon_entry *) NULL;
555 			if (new->nxt != (mon_entry *) NULL)
556 				new->nxt->prev = new;
557 			mon_table[hash].sm_monhdp = new;
558 		}
559 		mutex_unlock(&mon_table[hash].lock);
560 		return;
561 	}
562 }
563 
564 /*
565  * Deletes a specific monitor name or deletes all monitors with same id
566  * in hash table.
567  */
568 static void
569 delete_mon(mon_name, my_idp)
570 	char *mon_name;
571 	my_id *my_idp;
572 {
573 	unsigned int hash;
574 
575 	if (mon_name != (char *)NULL) {
576 		record_name(mon_name, 0);
577 		SMHASH(mon_name, hash);
578 		mutex_lock(&mon_table[hash].lock);
579 		delete_onemon(mon_name, my_idp, &mon_table[hash].sm_monhdp);
580 		mutex_unlock(&mon_table[hash].lock);
581 	} else {
582 		for (hash = 0; hash < MAX_HASHSIZE; hash++) {
583 			mutex_lock(&mon_table[hash].lock);
584 			delete_onemon(mon_name, my_idp,
585 					&mon_table[hash].sm_monhdp);
586 			mutex_unlock(&mon_table[hash].lock);
587 		}
588 	}
589 }
590 
591 /*
592  * Deletes a monitor in list.
593  * IF mon_name is NULL, delete all mon_names that have the same id,
594  * else delete specific monitor.
595  */
596 void
597 delete_onemon(mon_name, my_idp, monitor_q)
598 	char *mon_name;
599 	my_id *my_idp;
600 	mon_entry **monitor_q;
601 {
602 
603 	mon_entry *next, *nl;
604 	my_id *nl_idp;
605 
606 	next = *monitor_q;
607 	while ((nl = next) != (struct mon_entry *)NULL) {
608 		next = next->nxt;
609 		if (mon_name == (char *)NULL || (mon_name != (char *)NULL &&
610 			str_cmp_unqual_hostname(nl->id.mon_id.mon_name,
611 			mon_name) == 0)) {
612 			nl_idp = &nl->id.mon_id.my_id;
613 			if ((str_cmp_unqual_hostname(my_idp->my_name,
614 					nl_idp->my_name) == 0) &&
615 				my_idp->my_prog == nl_idp->my_prog &&
616 				my_idp->my_vers == nl_idp->my_vers &&
617 				my_idp->my_proc == nl_idp->my_proc) {
618 				/* found */
619 				if (debug)
620 					(void) printf("delete_mon(%x): %s\n",
621 							(int)nl, mon_name ?
622 							mon_name : "<NULL>");
623 				/*
624 				 * Remove the monitor name from the
625 				 * record_q, if id matches.
626 				 */
627 				record_name(nl->id.mon_id.mon_name, 0);
628 				/* if nl is not the first entry on list */
629 				if (nl->prev != (struct mon_entry *)NULL)
630 					nl->prev->nxt = nl->nxt;
631 				else {
632 					*monitor_q = nl->nxt;
633 				}
634 				if (nl->nxt != (struct mon_entry *)NULL)
635 					nl->nxt->prev = nl->prev;
636 				free(nl->id.mon_id.mon_name);
637 				free(nl_idp->my_name);
638 				free(nl);
639 			}
640 		} /* end of if mon */
641 	}
642 
643 }
644 /*
645  * Notify lockd of host specified by mon_name that the specified state
646  * has changed.
647  */
648 static void
649 send_notice(mon_name, state)
650 	char *mon_name;
651 	int state;
652 {
653 	struct mon_entry *next;
654 	mon_entry *monitor_q;
655 	unsigned int hash;
656 	moninfo_t *minfop;
657 	mon *monp;
658 
659 	SMHASH(mon_name, hash);
660 	mutex_lock(&mon_table[hash].lock);
661 	monitor_q = mon_table[hash].sm_monhdp;
662 
663 	next = monitor_q;
664 	while (next != (struct mon_entry *)NULL) {
665 		if (hostname_eq(next->id.mon_id.mon_name, mon_name)) {
666 			monp = &next->id;
667 			/*
668 			 * Prepare the minfop structure to pass to
669 			 * thr_create(). This structure is a copy of
670 			 * mon info and state.
671 			 */
672 			if ((minfop =
673 				(moninfo_t *)xmalloc(sizeof (moninfo_t))) !=
674 				(moninfo_t *)NULL) {
675 				(void) memcpy(&minfop->id, monp, sizeof (mon));
676 				/* Allocate entry for mon_name */
677 				if ((minfop->id.mon_id.mon_name =
678 					strdup(monp->mon_id.mon_name)) == 0) {
679 					syslog(LOG_ERR,
680 			"statd: send_notice: malloc error on mon %s (id=%d)\n",
681 						monp->mon_id.mon_name,
682 						* ((int *)monp->priv));
683 					free(minfop);
684 					continue;
685 				}
686 				/* Allocate entry for my_name */
687 				if ((minfop->id.mon_id.my_id.my_name =
688 				strdup(monp->mon_id.my_id.my_name)) == 0) {
689 					syslog(LOG_ERR,
690 			"statd: send_notice: malloc error on mon %s (id=%d)\n",
691 						monp->mon_id.mon_name,
692 						* ((int *)monp->priv));
693 					free(minfop->id.mon_id.mon_name);
694 					free(minfop);
695 					continue;
696 				}
697 				minfop->state = state;
698 				/*
699 				 * Create detached threads to process each host
700 				 * to notify.  If error, print out msg, free
701 				 * resources and continue.
702 				 */
703 				if (thr_create(NULL, NULL, thr_send_notice,
704 						(void *)minfop, THR_DETACHED,
705 						NULL)) {
706 				    syslog(LOG_ERR,
707 		"statd: unable to create thread to send_notice to %s.\n",
708 					mon_name);
709 				    free(minfop->id.mon_id.mon_name);
710 				    free(minfop->id.mon_id.my_id.my_name);
711 				    free(minfop);
712 				    continue;
713 				}
714 			}
715 		}
716 		next = next->nxt;
717 	}
718 	mutex_unlock(&mon_table[hash].lock);
719 }
720 
721 /*
722  * Work thread created to do the actual statd_call_lockd
723  */
724 static void *
725 thr_send_notice(void *arg)
726 {
727 	moninfo_t *minfop;
728 
729 	minfop = (moninfo_t *)arg;
730 
731 	if (statd_call_lockd(&minfop->id, minfop->state) == -1) {
732 		if (debug && minfop->id.mon_id.mon_name)
733 			(void) printf("problem with notifying %s failure, "
734 			    "give up\n", minfop->id.mon_id.mon_name);
735 	} else {
736 		if (debug)
737 			(void) printf("send_notice: %s, %d notified.\n",
738 			    minfop->id.mon_id.mon_name, minfop->state);
739 	}
740 
741 	free(minfop->id.mon_id.mon_name);
742 	free(minfop->id.mon_id.my_id.my_name);
743 	free(minfop);
744 
745 	thr_exit((void *) 0);
746 #ifdef lint
747 	/*NOTREACHED*/
748 	return ((void *)0);
749 #endif
750 }
751 
752 /*
753  * Contact lockd specified by monp.
754  */
755 static int
756 statd_call_lockd(monp, state)
757 	mon *monp;
758 	int state;
759 {
760 	enum clnt_stat clnt_stat;
761 	struct timeval tottimeout;
762 	struct status stat;
763 	my_id *my_idp;
764 	char *mon_name;
765 	int i;
766 	int rc = 0;
767 	CLIENT *clnt;
768 
769 	mon_name = monp->mon_id.mon_name;
770 	my_idp = &monp->mon_id.my_id;
771 	(void) memset(&stat, 0, sizeof (struct status));
772 	stat.mon_name = mon_name;
773 	stat.state = state;
774 	for (i = 0; i < 16; i++) {
775 		stat.priv[i] = monp->priv[i];
776 	}
777 	if (debug)
778 		(void) printf("statd_call_lockd: %s state = %d\n",
779 			stat.mon_name, stat.state);
780 
781 	tottimeout.tv_sec = SM_RPC_TIMEOUT;
782 	tottimeout.tv_usec = 0;
783 
784 	if ((clnt = create_client(my_idp->my_name, my_idp->my_prog,
785 		my_idp->my_vers, &tottimeout)) == (CLIENT *) NULL) {
786 			return (-1);
787 	}
788 
789 	clnt_stat = clnt_call(clnt, my_idp->my_proc, xdr_status, (char *)&stat,
790 				xdr_void, NULL, tottimeout);
791 	if (debug) {
792 		(void) printf("clnt_stat=%s(%d)\n",
793 			clnt_sperrno(clnt_stat), clnt_stat);
794 	}
795 	if (clnt_stat != (int)RPC_SUCCESS) {
796 		syslog(LOG_WARNING,
797 			"statd: cannot talk to lockd at %s, %s(%d)\n",
798 			my_idp->my_name, clnt_sperrno(clnt_stat), clnt_stat);
799 		rc = -1;
800 	}
801 
802 	clnt_destroy(clnt);
803 	return (rc);
804 
805 }
806 
807 /*
808  * Client handle created.
809  */
810 CLIENT *
811 create_client(host, prognum, versnum, utimeout)
812 	char	*host;
813 	int	prognum;
814 	int	versnum;
815 	struct timeval	*utimeout;
816 {
817 	int		fd;
818 	struct timeval	timeout;
819 	CLIENT		*client;
820 	struct t_info	tinfo;
821 
822 	if ((client = clnt_create_timed(host, prognum, versnum,
823 			"netpath", utimeout)) == NULL) {
824 		return (NULL);
825 	}
826 	(void) CLNT_CONTROL(client, CLGET_FD, (caddr_t)&fd);
827 	if (t_getinfo(fd, &tinfo) != -1) {
828 		if (tinfo.servtype == T_CLTS) {
829 			/*
830 			 * Set time outs for connectionless case
831 			 */
832 			timeout.tv_usec = 0;
833 			timeout.tv_sec = SM_CLTS_TIMEOUT;
834 			(void) CLNT_CONTROL(client,
835 				CLSET_RETRY_TIMEOUT, (caddr_t)&timeout);
836 		}
837 	} else
838 		return (NULL);
839 
840 	return (client);
841 }
842 
843 /*
844  * ONLY for debugging.
845  * Debug messages which prints out the monitor table information.
846  * If name is specified, just print out the hash list corresponding
847  * to name, otherwise print out the entire monitor table.
848  */
849 static void
850 pr_mon(name)
851 	char *name;
852 {
853 	mon_entry *nl;
854 	int hash;
855 
856 	if (!debug)
857 		return;
858 
859 	/* print all */
860 	if (name == NULL) {
861 		for (hash = 0; hash < MAX_HASHSIZE; hash++) {
862 			mutex_lock(&mon_table[hash].lock);
863 			nl = mon_table[hash].sm_monhdp;
864 			if (nl == (struct mon_entry *)NULL) {
865 				(void) printf(
866 					"*****monitor_q = NULL hash %d\n",
867 					hash);
868 				mutex_unlock(&mon_table[hash].lock);
869 				continue;
870 			}
871 			(void) printf("*****monitor_q:\n ");
872 			while (nl != (mon_entry *)NULL) {
873 				(void) printf("%s:(%x), ",
874 					nl->id.mon_id.mon_name, (int)nl);
875 				nl = nl->nxt;
876 			}
877 			mutex_unlock(&mon_table[hash].lock);
878 			(void) printf("\n");
879 		}
880 	} else { /* print one hash list */
881 		SMHASH(name, hash);
882 		mutex_lock(&mon_table[hash].lock);
883 		nl = mon_table[hash].sm_monhdp;
884 		if (nl == (struct mon_entry *)NULL) {
885 			(void) printf("*****monitor_q = NULL hash %d\n", hash);
886 		} else {
887 			(void) printf("*****monitor_q:\n ");
888 			while (nl != (mon_entry *)NULL) {
889 				(void) printf("%s:(%x), ",
890 					nl->id.mon_id.mon_name, (int)nl);
891 				nl = nl->nxt;
892 			}
893 			(void) printf("\n");
894 		}
895 		mutex_unlock(&mon_table[hash].lock);
896 	}
897 }
898 
899 /*
900  * Only for debugging.
901  * Dump the host name-to-address translation table passed in `name_addr'.
902  */
903 static void
904 pr_name_addr(name_addr_entry_t *name_addr)
905 {
906 	name_addr_entry_t *entry;
907 	addr_entry_t *addr;
908 	struct in_addr ipv4_addr;
909 	char *ipv6_addr;
910 	char abuf[INET6_ADDRSTRLEN];
911 
912 	assert(MUTEX_HELD(&name_addrlock));
913 	(void) printf("name-to-address translation table:\n");
914 	for (entry = name_addr; entry != NULL; entry = entry->next) {
915 		(void) printf("\t%s: ",
916 		    (entry->name ? entry->name : "(null)"));
917 		for (addr = entry->addresses; addr; addr = addr->next) {
918 			switch (addr->family) {
919 			case AF_INET:
920 				ipv4_addr = *(struct in_addr *)addr->ah.n_bytes;
921 				(void) printf(" %s (fam %d)",
922 				    inet_ntoa(ipv4_addr), addr->family);
923 				break;
924 			case AF_INET6:
925 				ipv6_addr = (char *)addr->ah.n_bytes;
926 				(void) printf(" %s (fam %d)",
927 				    inet_ntop(addr->family, ipv6_addr, abuf,
928 				    sizeof (abuf)), addr->family);
929 				break;
930 			default:
931 				return;
932 			}
933 		}
934 		printf("\n");
935 	}
936 }
937 
938 /*
939  * First, try to compare the hostnames as strings.  If the hostnames does not
940  * match we might deal with the hostname aliases.  In this case two different
941  * aliases for the same machine don't match each other when using strcmp.  To
942  * deal with this, the hostnames must be translated into some sort of universal
943  * identifier.  These identifiers can be compared.  Universal network addresses
944  * are currently used for this identifier because it is general and easy to do.
945  * Other schemes are possible and this routine could be converted if required.
946  *
947  * If it can't find an address for some reason, 0 is returned.
948  */
949 static int
950 hostname_eq(char *host1, char *host2)
951 {
952 	char *sysid1;
953 	char *sysid2;
954 	int rv;
955 
956 	/* Compare hostnames as strings */
957 	if (host1 != NULL && host2 != NULL && strcmp(host1, host2) == 0)
958 		return (1);
959 
960 	/* Try harder if hostnames do not match */
961 	sysid1 = get_system_id(host1);
962 	sysid2 = get_system_id(host2);
963 	if ((sysid1 == NULL) || (sysid2 == NULL))
964 		rv = 0;
965 	else
966 		rv = (strcmp(sysid1, sysid2) == 0);
967 	free(sysid1);
968 	free(sysid2);
969 	return (rv);
970 }
971 
972 /*
973  * Convert a hostname character string into its network address.
974  * A network address is found by searching through all the entries
975  * in /etc/netconfig and doing a netdir_getbyname() for each inet
976  * entry found.  The netbuf structure returned is converted into
977  * a universal address format.
978  *
979  * If a NULL hostname is given, then the name of the current host
980  * is used.  If the hostname doesn't map to an address, a NULL
981  * pointer is returned.
982  *
983  * N.B. the character string returned is allocated in taddr2uaddr()
984  * and should be freed by the caller using free().
985  */
986 static char *
987 get_system_id(char *hostname)
988 {
989 	void *hp;
990 	struct netconfig *ncp;
991 	struct nd_hostserv service;
992 	struct nd_addrlist *addrs;
993 	char *uaddr;
994 	int rv;
995 
996 	if (hostname == NULL)
997 		service.h_host = HOST_SELF;
998 	else
999 		service.h_host = hostname;
1000 	service.h_serv = NULL;
1001 	hp = setnetconfig();
1002 	if (hp == (void *) NULL) {
1003 		return (NULL);
1004 	}
1005 	while ((ncp = getnetconfig(hp)) != (struct netconfig *)NULL) {
1006 		if ((strcmp(ncp->nc_protofmly, NC_INET) == 0) ||
1007 		    (strcmp(ncp->nc_protofmly, NC_INET6) == 0)) {
1008 			addrs = NULL;
1009 			rv = netdir_getbyname(ncp, &service, &addrs);
1010 			if (rv != 0) {
1011 				continue;
1012 			}
1013 			if (addrs) {
1014 				uaddr = taddr2uaddr(ncp, addrs->n_addrs);
1015 				netdir_free(addrs, ND_ADDRLIST);
1016 				endnetconfig(hp);
1017 				return (uaddr);
1018 			}
1019 		}
1020 		else
1021 			continue;
1022 	}
1023 	endnetconfig(hp);
1024 	return (NULL);
1025 }
1026 
1027 void
1028 merge_hosts(void)
1029 {
1030 	struct lifconf *lifc = NULL;
1031 	int sock = -1;
1032 	struct lifreq *lifrp;
1033 	struct lifreq lifr;
1034 	int n;
1035 	struct sockaddr_in *sin;
1036 	struct sockaddr_in6 *sin6;
1037 	struct sockaddr_storage *sa;
1038 	int af;
1039 	struct hostent *phost;
1040 	char *addr;
1041 	size_t alen;
1042 	int errnum;
1043 
1044 	/*
1045 	 * This function will enumerate all the interfaces for
1046 	 * this platform, then get the hostent for each i/f.
1047 	 * With the hostent structure, we can get all of the
1048 	 * aliases for the i/f. Then we'll merge all the aliases
1049 	 * with the existing host_name[] list to come up with
1050 	 * all of the known names for each interface. This solves
1051 	 * the problem of a multi-homed host not knowing which
1052 	 * name to publish when statd is started. All the aliases
1053 	 * will be stored in the array, host_name.
1054 	 *
1055 	 * NOTE: Even though we will use all of the aliases we
1056 	 * can get from the i/f hostent, the receiving statd
1057 	 * will still need to handle aliases with hostname_eq.
1058 	 * This is because the sender's aliases may not match
1059 	 * those of the receiver.
1060 	 */
1061 	lifc = getmyaddrs();
1062 	if (lifc == (struct lifconf *)NULL) {
1063 		goto finish;
1064 	}
1065 	lifrp = lifc->lifc_req;
1066 	for (n = lifc->lifc_len / sizeof (struct lifreq); n > 0; n--, lifrp++) {
1067 
1068 		(void) strncpy(lifr.lifr_name, lifrp->lifr_name,
1069 		    sizeof (lifr.lifr_name));
1070 
1071 		af = lifrp->lifr_addr.ss_family;
1072 		sock = socket(af, SOCK_DGRAM, 0);
1073 		if (sock == -1) {
1074 			syslog(LOG_ERR, "statd: socket failed\n");
1075 			goto finish;
1076 		}
1077 
1078 		/* If it's the loopback interface, ignore */
1079 		if (ioctl(sock, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
1080 			syslog(LOG_ERR,
1081 			    "statd: SIOCGLIFFLAGS failed, error: %m\n");
1082 			goto finish;
1083 		}
1084 		if (lifr.lifr_flags & IFF_LOOPBACK)
1085 			continue;
1086 
1087 		if (ioctl(sock, SIOCGLIFADDR, (caddr_t)&lifr) < 0) {
1088 			syslog(LOG_ERR,
1089 			    "statd: SIOCGLIFADDR failed, error: %m\n");
1090 			goto finish;
1091 		}
1092 		sa = (struct sockaddr_storage *)&(lifr.lifr_addr);
1093 
1094 		if (sa->ss_family == AF_INET) {
1095 			sin = (struct sockaddr_in *)&lifr.lifr_addr;
1096 			addr = (char *)(&sin->sin_addr);
1097 			alen = sizeof (struct in_addr);
1098 		} else if (sa->ss_family == AF_INET6) {
1099 			sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
1100 			addr = (char *)(&sin6->sin6_addr);
1101 			alen = sizeof (struct in6_addr);
1102 		} else {
1103 			syslog(LOG_WARNING,
1104 			    "unexpected address family (%d)",
1105 			    sa->ss_family);
1106 			continue;
1107 		}
1108 
1109 		phost = getipnodebyaddr(addr, alen, sa->ss_family, &errnum);
1110 
1111 		if (phost)
1112 			add_aliases(phost);
1113 	}
1114 	/*
1115 	 * Now, just in case we didn't get them all byaddr,
1116 	 * let's look by name.
1117 	 */
1118 	phost = getipnodebyname(hostname, AF_INET6, AI_ALL, &errnum);
1119 
1120 	if (phost)
1121 		add_aliases(phost);
1122 
1123 finish:
1124 	if (sock != -1)
1125 		(void) close(sock);
1126 	if (lifc) {
1127 		free(lifc->lifc_buf);
1128 		free(lifc);
1129 	}
1130 }
1131 
1132 /*
1133  * add_aliases traverses a hostent alias list, compares
1134  * the aliases to the contents of host_name, and if an
1135  * alias is not already present, adds it to host_name[].
1136  */
1137 
1138 static void
1139 add_aliases(struct hostent *phost)
1140 {
1141 	char **aliases;
1142 
1143 	if (!in_host_array(phost->h_name)) {
1144 		add_to_host_array(phost->h_name);
1145 	}
1146 
1147 	if (phost->h_aliases == NULL)
1148 		return;			/* no aliases to register */
1149 
1150 	for (aliases = phost->h_aliases; *aliases != NULL; aliases++) {
1151 		if (!in_host_array(*aliases)) {
1152 			add_to_host_array(*aliases);
1153 		}
1154 	}
1155 }
1156 
1157 /*
1158  * in_host_array checks if the given hostname exists in the host_name
1159  * array. Returns 0 if the host doesn't exist, and 1 if it does exist
1160  */
1161 static int
1162 in_host_array(char *host)
1163 {
1164 	int i;
1165 
1166 	if (debug)
1167 		(void) printf("%s ", host);
1168 
1169 	if ((strcmp(hostname, host) == 0) || (strcmp(LOGHOST, host) == 0))
1170 		return (1);
1171 
1172 	for (i = 0; i < addrix; i++) {
1173 		if (strcmp(host_name[i], host) == 0)
1174 			return (1);
1175 	}
1176 
1177 	return (0);
1178 }
1179 
1180 /*
1181  * add_to_host_array adds a hostname to the host_name array. But if
1182  * the array is already full, then it first reallocates the array with
1183  * HOST_NAME_INCR extra elements. If the realloc fails, then it does
1184  * nothing and leaves host_name the way it was previous to the call.
1185  */
1186 static void
1187 add_to_host_array(char *host) {
1188 
1189 	void *new_block = NULL;
1190 
1191 	/* Make sure we don't overrun host_name. */
1192 	if (addrix >= host_name_count) {
1193 		host_name_count += HOST_NAME_INCR;
1194 		new_block = realloc((void *)host_name,
1195 				    host_name_count*sizeof (char *));
1196 		if (new_block != NULL)
1197 			host_name = new_block;
1198 		else {
1199 			host_name_count -= HOST_NAME_INCR;
1200 			return;
1201 		}
1202 	}
1203 
1204 	if ((host_name[addrix] = strdup(host)) != NULL)
1205 		addrix++;
1206 }
1207 
1208 /*
1209  * Compares the unqualified hostnames for hosts. Returns 0 if the
1210  * names match, and 1 if the names fail to match.
1211  */
1212 int
1213 str_cmp_unqual_hostname(char *rawname1, char *rawname2)
1214 {
1215 	size_t unq_len1, unq_len2;
1216 	char *domain;
1217 
1218 	if (debug) {
1219 		(void) printf("str_cmp_unqual: rawname1= %s, rawname2= %s\n",
1220 		    rawname1, rawname2);
1221 	}
1222 
1223 	unq_len1 = strcspn(rawname1, ".");
1224 	unq_len2 = strcspn(rawname2, ".");
1225 	domain = strchr(rawname1, '.');
1226 	if (domain != NULL) {
1227 		if ((strncmp(rawname1, SM_ADDR_IPV4, unq_len1) == 0) ||
1228 		    (strncmp(rawname1, SM_ADDR_IPV6, unq_len1) == 0))
1229 		return (1);
1230 	}
1231 
1232 	if ((unq_len1 == unq_len2) &&
1233 	    (strncmp(rawname1, rawname2, unq_len1) == 0)) {
1234 		return (0);
1235 	}
1236 
1237 	return (1);
1238 }
1239 
1240 /*
1241  * Compares <family>.<address-specifier> ASCII names for hosts.  Returns
1242  * 0 if the addresses match, and 1 if the addresses fail to match.
1243  * If the args are indeed specifiers, they should look like this:
1244  *
1245  *	ipv4.192.9.200.1 or ipv6.::C009:C801
1246  */
1247 int
1248 str_cmp_address_specifier(char *specifier1, char *specifier2)
1249 {
1250 	size_t unq_len1, unq_len2;
1251 	char *rawaddr1, *rawaddr2;
1252 	int af1, af2, len;
1253 
1254 	if (debug) {
1255 		(void) printf("str_cmp_addr: specifier1= %s, specifier2= %s\n",
1256 		    specifier1, specifier2);
1257 	}
1258 
1259 	/*
1260 	 * Verify that:
1261 	 *	1. The family tokens match;
1262 	 *	2. The IP addresses following the `.' are legal; and
1263 	 *	3. These addresses match.
1264 	 */
1265 	unq_len1 = strcspn(specifier1, ".");
1266 	unq_len2 = strcspn(specifier2, ".");
1267 	rawaddr1 = strchr(specifier1, '.');
1268 	rawaddr2 = strchr(specifier2, '.');
1269 
1270 	if (strncmp(specifier1, SM_ADDR_IPV4, unq_len1) == 0) {
1271 		af1 = AF_INET;
1272 		len = 4;
1273 	} else if (strncmp(specifier1, SM_ADDR_IPV6, unq_len1) == 0) {
1274 		af1 = AF_INET6;
1275 		len = 16;
1276 	}
1277 	else
1278 		return (1);
1279 
1280 	if (strncmp(specifier2, SM_ADDR_IPV4, unq_len2) == 0)
1281 		af2 = AF_INET;
1282 	else if (strncmp(specifier2, SM_ADDR_IPV6, unq_len2) == 0)
1283 		af2 = AF_INET6;
1284 	else
1285 		return (1);
1286 
1287 	if (af1 != af2)
1288 		return (1);
1289 
1290 	if (rawaddr1 != NULL && rawaddr2 != NULL) {
1291 		char dst1[16];
1292 		char dst2[16];
1293 		++rawaddr1;
1294 		++rawaddr2;
1295 
1296 		if (inet_pton(af1, rawaddr1, dst1) == 1 &&
1297 		    inet_pton(af2, rawaddr1, dst2) == 1 &&
1298 		    memcmp(dst1, dst2, len) == 0) {
1299 			return (0);
1300 		}
1301 	}
1302 	return (1);
1303 }
1304