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