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
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.
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]
24 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
28 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
29 * Use is subject to license terms.
32 * Copyright (c) 2012 by Delphix. All rights reserved.
35 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
36 /* All Rights Reserved */
39 * University Copyright- Copyright (c) 1982, 1986, 1988
40 * The Regents of the University of California
43 * University Acknowledgment- Portions of this document are derived from
44 * software developed by the University of California, Berkeley, and its
49 #include <sys/types.h>
55 #include <rpcsvc/sm_inter.h>
56 #include <rpcsvc/nsm_addr.h>
59 #include <sys/sockio.h>
60 #include <sys/socket.h>
61 #include <netinet/in.h>
62 #include <arpa/inet.h>
72 static int local_state
; /* fake local sm state */
73 /* client name-to-address translation table */
74 static name_addr_entry_t
*name_addr
= NULL
;
77 #define LOGHOST "loghost"
79 static void delete_mon(char *mon_name
, my_id
*my_idp
);
80 static void insert_mon(mon
*monp
);
81 static void pr_mon(char *);
82 static int statd_call_lockd(mon
*monp
, int state
);
83 static int hostname_eq(char *host1
, char *host2
);
84 static char *get_system_id(char *hostname
);
85 static void add_aliases(struct hostent
*phost
);
86 static void *thr_send_notice(void *);
87 static void delete_onemon(char *mon_name
, my_id
*my_idp
,
88 mon_entry
**monitor_q
);
89 static void send_notice(char *mon_name
, int state
);
90 static void add_to_host_array(char *host
);
91 static int in_host_array(char *host
);
92 static void pr_name_addr(name_addr_entry_t
*name_addr
);
94 extern int self_check(char *hostname
);
95 extern struct lifconf
*getmyaddrs(void);
99 sm_stat_svc(sm_name
*namep
, sm_stat_res
*resp
)
103 (void) printf("proc sm_stat: mon_name = %s\n",
106 resp
->res_stat
= stat_succ
;
107 resp
->state
= LOCAL_STATE
;
112 sm_mon_svc(mon
*monp
, sm_stat_res
*resp
)
115 monidp
= &monp
->mon_id
;
117 rw_rdlock(&thr_rwlock
);
119 (void) printf("proc sm_mon: mon_name = %s, id = %d\n",
120 monidp
->mon_name
, *((int *)monp
->priv
));
121 pr_mon(monp
->mon_id
.mon_name
);
124 /* only monitor other hosts */
125 if (self_check(monp
->mon_id
.mon_name
) == 0) {
126 /* store monitor request into monitor_q */
130 pr_mon(monp
->mon_id
.mon_name
);
131 resp
->res_stat
= stat_succ
;
132 resp
->state
= local_state
;
133 rw_unlock(&thr_rwlock
);
138 sm_unmon_svc(mon_id
*monidp
, sm_stat
*resp
)
140 rw_rdlock(&thr_rwlock
);
143 "proc sm_unmon: mon_name = %s, [%s, %d, %d, %d]\n",
144 monidp
->mon_name
, monidp
->my_id
.my_name
,
145 monidp
->my_id
.my_prog
, monidp
->my_id
.my_vers
,
146 monidp
->my_id
.my_proc
);
147 pr_mon(monidp
->mon_name
);
150 delete_mon(monidp
->mon_name
, &monidp
->my_id
);
151 pr_mon(monidp
->mon_name
);
152 resp
->state
= local_state
;
153 rw_unlock(&thr_rwlock
);
158 sm_unmon_all_svc(my_id
*myidp
, sm_stat
*resp
)
160 rw_rdlock(&thr_rwlock
);
162 (void) printf("proc sm_unmon_all: [%s, %d, %d, %d]\n",
164 myidp
->my_prog
, myidp
->my_vers
,
166 delete_mon(NULL
, myidp
);
168 resp
->state
= local_state
;
169 rw_unlock(&thr_rwlock
);
173 * Notifies lockd specified by name that state has changed for this server.
176 sm_notify_svc(stat_chge
*ntfp
)
178 rw_rdlock(&thr_rwlock
);
180 (void) printf("sm_notify: %s state =%d\n",
181 ntfp
->mon_name
, ntfp
->state
);
182 send_notice(ntfp
->mon_name
, ntfp
->state
);
183 rw_unlock(&thr_rwlock
);
188 sm_simu_crash_svc(void *myidp
)
191 struct mon_entry
*monitor_q
;
195 (void) printf("proc sm_simu_crash\n");
197 /* Only one crash should be running at a time. */
198 mutex_lock(&crash_lock
);
200 mutex_unlock(&crash_lock
);
204 mutex_unlock(&crash_lock
);
206 for (i
= 0; i
< MAX_HASHSIZE
; i
++) {
207 mutex_lock(&mon_table
[i
].lock
);
208 monitor_q
= mon_table
[i
].sm_monhdp
;
209 if (monitor_q
!= NULL
) {
210 mutex_unlock(&mon_table
[i
].lock
);
214 mutex_unlock(&mon_table
[i
].lock
);
217 * If there are entries found in the monitor table,
218 * initiate a crash, else zero out the in_crash variable.
221 mutex_lock(&crash_lock
);
223 /* Signal sm_try() thread if sleeping. */
224 cond_signal(&retrywait
);
225 mutex_unlock(&crash_lock
);
226 rw_wrlock(&thr_rwlock
);
228 rw_unlock(&thr_rwlock
);
230 mutex_lock(&crash_lock
);
232 mutex_unlock(&crash_lock
);
238 nsmaddrproc1_reg(reg1args
*regargs
, reg1res
*regresp
)
241 name_addr_entry_t
*entry
;
245 rw_rdlock(&thr_rwlock
);
249 (void) printf("nap1_reg: fam= %d, name= %s, len= %d\n",
250 regargs
->family
, regargs
->name
, regargs
->address
.n_len
);
251 (void) printf("address is: ");
252 for (i
= 0; i
< regargs
->address
.n_len
; i
++) {
254 (unsigned char)regargs
->address
.n_bytes
[i
]);
260 * Locate the entry with the name in the NSM_ADDR_REG request if
261 * it exists. If it doesn't, create a new entry to hold this name.
262 * The first time through this code, name_addr starts out as NULL.
264 mutex_lock(&name_addrlock
);
265 for (entry
= name_addr
; entry
; entry
= entry
->next
) {
266 if (strcmp(regargs
->name
, entry
->name
) == 0) {
268 (void) printf("nap1_reg: matched name %s\n",
276 entry
= (name_addr_entry_t
*)malloc(sizeof (*entry
));
280 "nsmaddrproc1_reg: no memory for entry\n");
282 status
= nsm_addr_fail
;
286 entry
->name
= strdup(regargs
->name
);
287 if (entry
->name
== NULL
) {
290 "nsmaddrproc1_reg: no memory for name\n");
293 status
= nsm_addr_fail
;
296 entry
->addresses
= NULL
;
299 * Link the new entry onto the *head* of the name_addr
302 * Note: there is code below in the address maintenance
303 * section that assumes this behavior.
305 entry
->next
= name_addr
;
310 * Try to match the address in the request; if it doesn't match,
311 * add it to the entry's address list.
313 for (addr
= entry
->addresses
; addr
; addr
= addr
->next
) {
314 if (addr
->family
== (sa_family_t
)regargs
->family
&&
315 addr
->ah
.n_len
== regargs
->address
.n_len
&&
316 memcmp(addr
->ah
.n_bytes
, regargs
->address
.n_bytes
,
317 addr
->ah
.n_len
) == 0) {
321 (void) printf("nap1_reg: matched addr ");
322 for (i
= 0; i
< addr
->ah
.n_len
; i
++) {
324 (unsigned char)addr
->ah
.n_bytes
[i
]);
326 (void) printf(" family %d for name %s\n",
327 addr
->family
, entry
->name
);
334 addr
= (addr_entry_t
*)malloc(sizeof (*addr
));
335 tmp_n_bytes
= (char *)malloc(regargs
->address
.n_len
);
336 if (addr
== NULL
|| tmp_n_bytes
== NULL
) {
338 (void) printf("nap1_reg: no memory for addr\n");
342 * If this name entry was just newly made in the
343 * table, back it out now that we can't register
344 * an address with it anyway.
346 * Note: we are making an assumption about how
347 * names are added to (the head of) name_addr here.
349 if (entry
== name_addr
&& entry
->addresses
== NULL
) {
350 name_addr
= name_addr
->next
;
357 status
= nsm_addr_fail
;
363 * Note: this check for address family assumes that we
364 * will get something different here someday for
365 * other supported address types, such as IPv6.
367 addr
->ah
.n_len
= regargs
->address
.n_len
;
368 addr
->ah
.n_bytes
= tmp_n_bytes
;
369 addr
->family
= regargs
->family
;
371 if ((addr
->family
!= AF_INET
) &&
372 (addr
->family
!= AF_INET6
)) {
374 "nap1_reg: unknown addr family %d\n",
378 (void) memcpy(addr
->ah
.n_bytes
, regargs
->address
.n_bytes
,
381 addr
->next
= entry
->addresses
;
382 entry
->addresses
= addr
;
385 status
= nsm_addr_succ
;
388 regresp
->status
= status
;
390 pr_name_addr(name_addr
);
392 mutex_unlock(&name_addrlock
);
393 rw_unlock(&thr_rwlock
);
397 * Insert an entry into the monitor_q. Space for the entry is allocated
398 * here. It is then filled in from the information passed in.
401 insert_mon(mon
*monp
)
403 mon_entry
*new, *found
;
404 my_id
*my_idp
, *nl_idp
;
405 mon_entry
*monitor_q
;
407 name_addr_entry_t
*entry
;
410 /* Allocate entry for new */
411 if ((new = (mon_entry
*) malloc(sizeof (mon_entry
))) == 0) {
413 "statd: insert_mon: malloc error on mon %s (id=%d)\n",
414 monp
->mon_id
.mon_name
, *((int *)monp
->priv
));
418 /* Initialize and copy contents of monp to new */
419 (void) memset(new, 0, sizeof (mon_entry
));
420 (void) memcpy(&new->id
, monp
, sizeof (mon
));
422 /* Allocate entry for new mon_name */
423 if ((new->id
.mon_id
.mon_name
= strdup(monp
->mon_id
.mon_name
)) == 0) {
425 "statd: insert_mon: malloc error on mon %s (id=%d)\n",
426 monp
->mon_id
.mon_name
, *((int *)monp
->priv
));
432 /* Allocate entry for new my_name */
433 if ((new->id
.mon_id
.my_id
.my_name
=
434 strdup(monp
->mon_id
.my_id
.my_name
)) == 0) {
436 "statd: insert_mon: malloc error on mon %s (id=%d)\n",
437 monp
->mon_id
.mon_name
, *((int *)monp
->priv
));
438 free(new->id
.mon_id
.mon_name
);
444 (void) printf("add_mon(%x) %s (id=%d)\n",
445 (int)new, new->id
.mon_id
.mon_name
, *((int *)new->id
.priv
));
448 * Record the name, and all addresses which have been registered
449 * for this name, in the filesystem name space.
451 record_name(new->id
.mon_id
.mon_name
, 1);
452 if (regfiles_only
== 0) {
453 mutex_lock(&name_addrlock
);
454 for (entry
= name_addr
; entry
; entry
= entry
->next
) {
455 if (strcmp(new->id
.mon_id
.mon_name
, entry
->name
) != 0) {
459 for (addr
= entry
->addresses
; addr
; addr
= addr
->next
) {
460 record_addr(new->id
.mon_id
.mon_name
,
461 addr
->family
, &addr
->ah
);
465 mutex_unlock(&name_addrlock
);
468 SMHASH(new->id
.mon_id
.mon_name
, hash
);
469 mutex_lock(&mon_table
[hash
].lock
);
470 monitor_q
= mon_table
[hash
].sm_monhdp
;
472 /* If mon_table hash list is empty. */
473 if (monitor_q
== NULL
) {
475 (void) printf("\nAdding to monitor_q hash %d\n", hash
);
476 new->nxt
= new->prev
= NULL
;
477 mon_table
[hash
].sm_monhdp
= new;
478 mutex_unlock(&mon_table
[hash
].lock
);
482 my_idp
= &new->id
.mon_id
.my_id
;
483 while (monitor_q
!= NULL
) {
485 * This list is searched sequentially for the
486 * tuple (hostname, prog, vers, proc). The tuples
487 * are inserted in the beginning of the monitor_q,
488 * if the hostname is not already present in the list.
489 * If the hostname is found in the list, the incoming
490 * tuple is inserted just after all the tuples with the
491 * same hostname. However, if the tuple matches exactly
492 * with an entry in the list, space allocated for the
493 * new entry is released and nothing is inserted in the
497 if (str_cmp_unqual_hostname(
498 monitor_q
->id
.mon_id
.mon_name
,
499 new->id
.mon_id
.mon_name
) == 0) {
501 nl_idp
= &monitor_q
->id
.mon_id
.my_id
;
502 if ((str_cmp_unqual_hostname(my_idp
->my_name
,
503 nl_idp
->my_name
) == 0) &&
504 my_idp
->my_prog
== nl_idp
->my_prog
&&
505 my_idp
->my_vers
== nl_idp
->my_vers
&&
506 my_idp
->my_proc
== nl_idp
->my_proc
) {
508 * already exists an identical one,
509 * release the space allocated for the
512 free(new->id
.mon_id
.mon_name
);
513 free(new->id
.mon_id
.my_id
.my_name
);
515 mutex_unlock(&mon_table
[hash
].lock
);
519 * mark the last callback that is
520 * not matching; new is inserted
527 monitor_q
= monitor_q
->nxt
;
531 * insert just after the entry having matching tuple.
533 new->nxt
= found
->nxt
;
535 if (found
->nxt
!= NULL
)
536 found
->nxt
->prev
= new;
540 * not found, insert in front of list.
542 new->nxt
= mon_table
[hash
].sm_monhdp
;
543 new->prev
= (mon_entry
*) NULL
;
544 if (new->nxt
!= (mon_entry
*) NULL
)
545 new->nxt
->prev
= new;
546 mon_table
[hash
].sm_monhdp
= new;
548 mutex_unlock(&mon_table
[hash
].lock
);
554 * Deletes a specific monitor name or deletes all monitors with same id
558 delete_mon(char *mon_name
, my_id
*my_idp
)
562 if (mon_name
!= NULL
) {
563 record_name(mon_name
, 0);
564 SMHASH(mon_name
, hash
);
565 mutex_lock(&mon_table
[hash
].lock
);
566 delete_onemon(mon_name
, my_idp
, &mon_table
[hash
].sm_monhdp
);
567 mutex_unlock(&mon_table
[hash
].lock
);
569 for (hash
= 0; hash
< MAX_HASHSIZE
; hash
++) {
570 mutex_lock(&mon_table
[hash
].lock
);
571 delete_onemon(mon_name
, my_idp
,
572 &mon_table
[hash
].sm_monhdp
);
573 mutex_unlock(&mon_table
[hash
].lock
);
579 * Deletes a monitor in list.
580 * IF mon_name is NULL, delete all mon_names that have the same id,
581 * else delete specific monitor.
584 delete_onemon(char *mon_name
, my_id
*my_idp
, mon_entry
**monitor_q
)
587 mon_entry
*next
, *nl
;
591 while ((nl
= next
) != NULL
) {
593 if (mon_name
== NULL
|| (mon_name
!= NULL
&&
594 str_cmp_unqual_hostname(nl
->id
.mon_id
.mon_name
,
596 nl_idp
= &nl
->id
.mon_id
.my_id
;
597 if ((str_cmp_unqual_hostname(my_idp
->my_name
,
598 nl_idp
->my_name
) == 0) &&
599 my_idp
->my_prog
== nl_idp
->my_prog
&&
600 my_idp
->my_vers
== nl_idp
->my_vers
&&
601 my_idp
->my_proc
== nl_idp
->my_proc
) {
604 (void) printf("delete_mon(%x): %s\n",
606 mon_name
: "<NULL>");
608 * Remove the monitor name from the
609 * record_q, if id matches.
611 record_name(nl
->id
.mon_id
.mon_name
, 0);
612 /* if nl is not the first entry on list */
613 if (nl
->prev
!= NULL
)
614 nl
->prev
->nxt
= nl
->nxt
;
616 *monitor_q
= nl
->nxt
;
619 nl
->nxt
->prev
= nl
->prev
;
620 free(nl
->id
.mon_id
.mon_name
);
621 free(nl_idp
->my_name
);
624 } /* end of if mon */
629 * Notify lockd of host specified by mon_name that the specified state
633 send_notice(char *mon_name
, int state
)
635 struct mon_entry
*next
;
636 mon_entry
*monitor_q
;
641 SMHASH(mon_name
, hash
);
642 mutex_lock(&mon_table
[hash
].lock
);
643 monitor_q
= mon_table
[hash
].sm_monhdp
;
646 while (next
!= NULL
) {
647 if (hostname_eq(next
->id
.mon_id
.mon_name
, mon_name
)) {
650 * Prepare the minfop structure to pass to
651 * thr_create(). This structure is a copy of
652 * mon info and state.
655 (moninfo_t
*)xmalloc(sizeof (moninfo_t
))) != NULL
) {
656 (void) memcpy(&minfop
->id
, monp
, sizeof (mon
));
657 /* Allocate entry for mon_name */
658 if ((minfop
->id
.mon_id
.mon_name
=
659 strdup(monp
->mon_id
.mon_name
)) == 0) {
660 syslog(LOG_ERR
, "statd: send_notice: "
661 "malloc error on mon %s (id=%d)\n",
662 monp
->mon_id
.mon_name
,
663 *((int *)monp
->priv
));
667 /* Allocate entry for my_name */
668 if ((minfop
->id
.mon_id
.my_id
.my_name
=
669 strdup(monp
->mon_id
.my_id
.my_name
)) == 0) {
670 syslog(LOG_ERR
, "statd: send_notice: "
671 "malloc error on mon %s (id=%d)\n",
672 monp
->mon_id
.mon_name
,
673 *((int *)monp
->priv
));
674 free(minfop
->id
.mon_id
.mon_name
);
678 minfop
->state
= state
;
680 * Create detached threads to process each host
681 * to notify. If error, print out msg, free
682 * resources and continue.
684 if (thr_create(NULL
, NULL
, thr_send_notice
,
685 minfop
, THR_DETACHED
, NULL
)) {
686 syslog(LOG_ERR
, "statd: unable to "
687 "create thread to send_notice to "
689 free(minfop
->id
.mon_id
.mon_name
);
690 free(minfop
->id
.mon_id
.my_id
.my_name
);
698 mutex_unlock(&mon_table
[hash
].lock
);
702 * Work thread created to do the actual statd_call_lockd
705 thr_send_notice(void *arg
)
709 minfop
= (moninfo_t
*)arg
;
710 if (statd_call_lockd(&minfop
->id
, minfop
->state
) == -1) {
711 if (debug
&& minfop
->id
.mon_id
.mon_name
)
712 (void) printf("problem with notifying %s failure, "
713 "give up\n", minfop
->id
.mon_id
.mon_name
);
716 (void) printf("send_notice: %s, %d notified.\n",
717 minfop
->id
.mon_id
.mon_name
, minfop
->state
);
720 free(minfop
->id
.mon_id
.mon_name
);
721 free(minfop
->id
.mon_id
.my_id
.my_name
);
724 thr_exit((void *) 0);
732 * Contact lockd specified by monp.
735 statd_call_lockd(mon
*monp
, int state
)
737 enum clnt_stat clnt_stat
;
738 struct timeval tottimeout
;
739 struct sm_status stat
;
746 mon_name
= monp
->mon_id
.mon_name
;
747 my_idp
= &monp
->mon_id
.my_id
;
748 (void) memset(&stat
, 0, sizeof (stat
));
749 stat
.mon_name
= mon_name
;
751 for (i
= 0; i
< 16; i
++) {
752 stat
.priv
[i
] = monp
->priv
[i
];
755 (void) printf("statd_call_lockd: %s state = %d\n",
756 stat
.mon_name
, stat
.state
);
758 tottimeout
.tv_sec
= SM_RPC_TIMEOUT
;
759 tottimeout
.tv_usec
= 0;
761 clnt
= create_client(my_idp
->my_name
, my_idp
->my_prog
, my_idp
->my_vers
,
762 "ticotsord", &tottimeout
);
767 clnt_stat
= clnt_call(clnt
, my_idp
->my_proc
, xdr_sm_status
,
768 (char *)&stat
, xdr_void
, NULL
, tottimeout
);
770 (void) printf("clnt_stat=%s(%d)\n",
771 clnt_sperrno(clnt_stat
), clnt_stat
);
773 if (clnt_stat
!= (int)RPC_SUCCESS
) {
775 "statd: cannot talk to lockd at %s, %s(%d)\n",
776 my_idp
->my_name
, clnt_sperrno(clnt_stat
), clnt_stat
);
786 * Client handle created.
789 create_client(char *host
, int prognum
, int versnum
, char *netid
,
790 struct timeval
*utimeout
)
793 struct timeval timeout
;
798 client
= clnt_create_timed(host
, prognum
, versnum
,
799 "netpath", utimeout
);
801 struct netconfig
*nconf
;
803 nconf
= getnetconfigent(netid
);
808 client
= clnt_tp_create_timed(host
, prognum
, versnum
, nconf
,
811 freenetconfigent(nconf
);
814 if (client
== NULL
) {
818 (void) CLNT_CONTROL(client
, CLGET_FD
, (caddr_t
)&fd
);
819 if (t_getinfo(fd
, &tinfo
) != -1) {
820 if (tinfo
.servtype
== T_CLTS
) {
822 * Set time outs for connectionless case
825 timeout
.tv_sec
= SM_CLTS_TIMEOUT
;
826 (void) CLNT_CONTROL(client
,
827 CLSET_RETRY_TIMEOUT
, (caddr_t
)&timeout
);
836 * ONLY for debugging.
837 * Debug messages which prints out the monitor table information.
838 * If name is specified, just print out the hash list corresponding
839 * to name, otherwise print out the entire monitor table.
852 for (hash
= 0; hash
< MAX_HASHSIZE
; hash
++) {
853 mutex_lock(&mon_table
[hash
].lock
);
854 nl
= mon_table
[hash
].sm_monhdp
;
857 "*****monitor_q = NULL hash %d\n", hash
);
858 mutex_unlock(&mon_table
[hash
].lock
);
861 (void) printf("*****monitor_q:\n ");
863 (void) printf("%s:(%x), ",
864 nl
->id
.mon_id
.mon_name
, (int)nl
);
867 mutex_unlock(&mon_table
[hash
].lock
);
870 } else { /* print one hash list */
872 mutex_lock(&mon_table
[hash
].lock
);
873 nl
= mon_table
[hash
].sm_monhdp
;
875 (void) printf("*****monitor_q = NULL hash %d\n", hash
);
877 (void) printf("*****monitor_q:\n ");
879 (void) printf("%s:(%x), ",
880 nl
->id
.mon_id
.mon_name
, (int)nl
);
885 mutex_unlock(&mon_table
[hash
].lock
);
890 * Only for debugging.
891 * Dump the host name-to-address translation table passed in `name_addr'.
894 pr_name_addr(name_addr_entry_t
*name_addr
)
896 name_addr_entry_t
*entry
;
898 struct in_addr ipv4_addr
;
900 char abuf
[INET6_ADDRSTRLEN
];
902 assert(MUTEX_HELD(&name_addrlock
));
903 (void) printf("name-to-address translation table:\n");
904 for (entry
= name_addr
; entry
!= NULL
; entry
= entry
->next
) {
905 (void) printf("\t%s: ",
906 (entry
->name
? entry
->name
: "(null)"));
907 for (addr
= entry
->addresses
; addr
; addr
= addr
->next
) {
908 switch (addr
->family
) {
910 ipv4_addr
= *(struct in_addr
*)addr
->ah
.n_bytes
;
911 (void) printf(" %s (fam %d)",
912 inet_ntoa(ipv4_addr
), addr
->family
);
915 ipv6_addr
= (char *)addr
->ah
.n_bytes
;
916 (void) printf(" %s (fam %d)",
917 inet_ntop(addr
->family
, ipv6_addr
, abuf
,
918 sizeof (abuf
)), addr
->family
);
929 * First, try to compare the hostnames as strings. If the hostnames does not
930 * match we might deal with the hostname aliases. In this case two different
931 * aliases for the same machine don't match each other when using strcmp. To
932 * deal with this, the hostnames must be translated into some sort of universal
933 * identifier. These identifiers can be compared. Universal network addresses
934 * are currently used for this identifier because it is general and easy to do.
935 * Other schemes are possible and this routine could be converted if required.
937 * If it can't find an address for some reason, 0 is returned.
940 hostname_eq(char *host1
, char *host2
)
946 /* Compare hostnames as strings */
947 if (host1
!= NULL
&& host2
!= NULL
&& strcmp(host1
, host2
) == 0)
950 /* Try harder if hostnames do not match */
951 sysid1
= get_system_id(host1
);
952 sysid2
= get_system_id(host2
);
953 if ((sysid1
== NULL
) || (sysid2
== NULL
))
956 rv
= (strcmp(sysid1
, sysid2
) == 0);
963 * Convert a hostname character string into its network address.
964 * A network address is found by searching through all the entries
965 * in /etc/netconfig and doing a netdir_getbyname() for each inet
966 * entry found. The netbuf structure returned is converted into
967 * a universal address format.
969 * If a NULL hostname is given, then the name of the current host
970 * is used. If the hostname doesn't map to an address, a NULL
971 * pointer is returned.
973 * N.B. the character string returned is allocated in taddr2uaddr()
974 * and should be freed by the caller using free().
977 get_system_id(char *hostname
)
980 struct netconfig
*ncp
;
981 struct nd_hostserv service
;
982 struct nd_addrlist
*addrs
;
986 if (hostname
== NULL
)
987 service
.h_host
= HOST_SELF
;
989 service
.h_host
= hostname
;
990 service
.h_serv
= NULL
;
992 if (hp
== (void *) NULL
) {
995 while ((ncp
= getnetconfig(hp
)) != NULL
) {
996 if ((strcmp(ncp
->nc_protofmly
, NC_INET
) == 0) ||
997 (strcmp(ncp
->nc_protofmly
, NC_INET6
) == 0)) {
999 rv
= netdir_getbyname(ncp
, &service
, &addrs
);
1004 uaddr
= taddr2uaddr(ncp
, addrs
->n_addrs
);
1005 netdir_free(addrs
, ND_ADDRLIST
);
1020 struct lifconf
*lifc
= NULL
;
1022 struct lifreq
*lifrp
;
1025 struct sockaddr_in
*sin
;
1026 struct sockaddr_in6
*sin6
;
1027 struct sockaddr_storage
*sa
;
1029 struct hostent
*phost
;
1035 * This function will enumerate all the interfaces for
1036 * this platform, then get the hostent for each i/f.
1037 * With the hostent structure, we can get all of the
1038 * aliases for the i/f. Then we'll merge all the aliases
1039 * with the existing host_name[] list to come up with
1040 * all of the known names for each interface. This solves
1041 * the problem of a multi-homed host not knowing which
1042 * name to publish when statd is started. All the aliases
1043 * will be stored in the array, host_name.
1045 * NOTE: Even though we will use all of the aliases we
1046 * can get from the i/f hostent, the receiving statd
1047 * will still need to handle aliases with hostname_eq.
1048 * This is because the sender's aliases may not match
1049 * those of the receiver.
1051 lifc
= getmyaddrs();
1055 lifrp
= lifc
->lifc_req
;
1056 for (n
= lifc
->lifc_len
/ sizeof (struct lifreq
); n
> 0; n
--, lifrp
++) {
1058 (void) strncpy(lifr
.lifr_name
, lifrp
->lifr_name
,
1059 sizeof (lifr
.lifr_name
));
1061 af
= lifrp
->lifr_addr
.ss_family
;
1062 sock
= socket(af
, SOCK_DGRAM
, 0);
1064 syslog(LOG_ERR
, "statd: socket failed\n");
1068 /* If it's the loopback interface, ignore */
1069 if (ioctl(sock
, SIOCGLIFFLAGS
, (caddr_t
)&lifr
) < 0) {
1071 "statd: SIOCGLIFFLAGS failed, error: %m\n");
1074 if (lifr
.lifr_flags
& IFF_LOOPBACK
)
1077 if (ioctl(sock
, SIOCGLIFADDR
, (caddr_t
)&lifr
) < 0) {
1079 "statd: SIOCGLIFADDR failed, error: %m\n");
1082 sa
= (struct sockaddr_storage
*)&(lifr
.lifr_addr
);
1084 if (sa
->ss_family
== AF_INET
) {
1085 sin
= (struct sockaddr_in
*)&lifr
.lifr_addr
;
1086 addr
= (char *)(&sin
->sin_addr
);
1087 alen
= sizeof (struct in_addr
);
1088 } else if (sa
->ss_family
== AF_INET6
) {
1089 sin6
= (struct sockaddr_in6
*)&lifr
.lifr_addr
;
1090 addr
= (char *)(&sin6
->sin6_addr
);
1091 alen
= sizeof (struct in6_addr
);
1094 "unexpected address family (%d)",
1099 phost
= getipnodebyaddr(addr
, alen
, sa
->ss_family
, &errnum
);
1105 * Now, just in case we didn't get them all byaddr,
1106 * let's look by name.
1108 phost
= getipnodebyname(hostname
, AF_INET6
, AI_ALL
, &errnum
);
1117 free(lifc
->lifc_buf
);
1123 * add_aliases traverses a hostent alias list, compares
1124 * the aliases to the contents of host_name, and if an
1125 * alias is not already present, adds it to host_name[].
1129 add_aliases(struct hostent
*phost
)
1133 if (!in_host_array(phost
->h_name
)) {
1134 add_to_host_array(phost
->h_name
);
1137 if (phost
->h_aliases
== NULL
)
1138 return; /* no aliases to register */
1140 for (aliases
= phost
->h_aliases
; *aliases
!= NULL
; aliases
++) {
1141 if (!in_host_array(*aliases
)) {
1142 add_to_host_array(*aliases
);
1148 * in_host_array checks if the given hostname exists in the host_name
1149 * array. Returns 0 if the host doesn't exist, and 1 if it does exist
1152 in_host_array(char *host
)
1157 (void) printf("%s ", host
);
1159 if ((strcmp(hostname
, host
) == 0) || (strcmp(LOGHOST
, host
) == 0))
1162 for (i
= 0; i
< addrix
; i
++) {
1163 if (strcmp(host_name
[i
], host
) == 0)
1171 * add_to_host_array adds a hostname to the host_name array. But if
1172 * the array is already full, then it first reallocates the array with
1173 * HOST_NAME_INCR extra elements. If the realloc fails, then it does
1174 * nothing and leaves host_name the way it was previous to the call.
1177 add_to_host_array(char *host
) {
1179 void *new_block
= NULL
;
1181 /* Make sure we don't overrun host_name. */
1182 if (addrix
>= host_name_count
) {
1183 host_name_count
+= HOST_NAME_INCR
;
1184 new_block
= realloc((void *)host_name
,
1185 host_name_count
*sizeof (char *));
1186 if (new_block
!= NULL
)
1187 host_name
= new_block
;
1189 host_name_count
-= HOST_NAME_INCR
;
1194 if ((host_name
[addrix
] = strdup(host
)) != NULL
)
1199 * Compares the unqualified hostnames for hosts. Returns 0 if the
1200 * names match, and 1 if the names fail to match.
1203 str_cmp_unqual_hostname(char *rawname1
, char *rawname2
)
1205 size_t unq_len1
, unq_len2
;
1209 (void) printf("str_cmp_unqual: rawname1= %s, rawname2= %s\n",
1210 rawname1
, rawname2
);
1213 unq_len1
= strcspn(rawname1
, ".");
1214 unq_len2
= strcspn(rawname2
, ".");
1215 domain
= strchr(rawname1
, '.');
1216 if (domain
!= NULL
) {
1217 if ((strncmp(rawname1
, SM_ADDR_IPV4
, unq_len1
) == 0) ||
1218 (strncmp(rawname1
, SM_ADDR_IPV6
, unq_len1
) == 0))
1222 if ((unq_len1
== unq_len2
) &&
1223 (strncmp(rawname1
, rawname2
, unq_len1
) == 0)) {
1231 * Compares <family>.<address-specifier> ASCII names for hosts. Returns
1232 * 0 if the addresses match, and 1 if the addresses fail to match.
1233 * If the args are indeed specifiers, they should look like this:
1235 * ipv4.192.9.200.1 or ipv6.::C009:C801
1238 str_cmp_address_specifier(char *specifier1
, char *specifier2
)
1240 size_t unq_len1
, unq_len2
;
1241 char *rawaddr1
, *rawaddr2
;
1245 (void) printf("str_cmp_addr: specifier1= %s, specifier2= %s\n",
1246 specifier1
, specifier2
);
1251 * 1. The family tokens match;
1252 * 2. The IP addresses following the `.' are legal; and
1253 * 3. These addresses match.
1255 unq_len1
= strcspn(specifier1
, ".");
1256 unq_len2
= strcspn(specifier2
, ".");
1257 rawaddr1
= strchr(specifier1
, '.');
1258 rawaddr2
= strchr(specifier2
, '.');
1260 if (strncmp(specifier1
, SM_ADDR_IPV4
, unq_len1
) == 0) {
1263 } else if (strncmp(specifier1
, SM_ADDR_IPV6
, unq_len1
) == 0) {
1270 if (strncmp(specifier2
, SM_ADDR_IPV4
, unq_len2
) == 0)
1272 else if (strncmp(specifier2
, SM_ADDR_IPV6
, unq_len2
) == 0)
1280 if (rawaddr1
!= NULL
&& rawaddr2
!= NULL
) {
1286 if (inet_pton(af1
, rawaddr1
, dst1
) == 1 &&
1287 inet_pton(af2
, rawaddr1
, dst2
) == 1 &&
1288 memcmp(dst1
, dst2
, len
) == 0) {
1296 * Add IP address strings to the host_name list.
1301 struct ifaddrs
*ifap
, *cifap
;
1304 error
= getifaddrs(&ifap
);
1306 syslog(LOG_WARNING
, "getifaddrs error: '%s'",
1311 for (cifap
= ifap
; cifap
!= NULL
; cifap
= cifap
->ifa_next
) {
1312 struct sockaddr
*sa
= cifap
->ifa_addr
;
1313 char addr_str
[INET6_ADDRSTRLEN
];
1316 switch (sa
->sa_family
) {
1318 struct sockaddr_in
*sin
= (struct sockaddr_in
*)sa
;
1320 /* Skip loopback addresses. */
1321 if (sin
->sin_addr
.s_addr
== htonl(INADDR_LOOPBACK
)) {
1325 addr
= &sin
->sin_addr
;
1330 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)sa
;
1332 /* Skip loopback addresses. */
1333 if (IN6_IS_ADDR_LOOPBACK(&sin6
->sin6_addr
)) {
1337 addr
= &sin6
->sin6_addr
;
1342 syslog(LOG_WARNING
, "Unknown address family %d for "
1343 "interface %s", sa
->sa_family
, cifap
->ifa_name
);
1347 if (inet_ntop(sa
->sa_family
, addr
, addr_str
, sizeof (addr_str
))
1349 syslog(LOG_WARNING
, "Failed to convert address into "
1350 "string representation for interface '%s' "
1351 "address family %d", cifap
->ifa_name
,
1356 if (!in_host_array(addr_str
)) {
1357 add_to_host_array(addr_str
);