xref: /titanic_41/usr/src/cmd/avs/dscfglockd/dscfglockd.c (revision 5fbb41393be5d63f75952b1d72d4df2642d22557)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <signal.h>
27 #include <sys/types.h>
28 #include <sys/time.h>
29 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <netinet/tcp.h>
32 #include <arpa/inet.h>
33 #include <netdb.h>
34 #include <fcntl.h>
35 #include <string.h>
36 #include <memory.h>
37 #include <sys/param.h>
38 #include <sys/pathconf.h>
39 #include <netdir.h>
40 #include <netconfig.h>
41 #include <sys/sockio.h>
42 #include <net/if.h>
43 #include <sys/resource.h>
44 #include <stdio.h>
45 #include <errno.h>
46 #include <assert.h>
47 #include <locale.h>
48 #include <unistd.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <strings.h>
52 #include <sys/unistat/spcs_s.h>
53 #include <sys/unistat/spcs_s_u.h>
54 #include <sys/unistat/spcs_errors.h>
55 
56 #include <sys/nsctl/cfg.h>
57 #include <sys/nsctl/cfg_lockd.h>
58 
59 #ifdef DEBUG
60 #define	DPF(m)		if (debug) (void) fprintf m
61 #else
62 #define	DPF(m)
63 #endif
64 
65 #ifdef	TTY_MESSAGES
66 #define	CLOSE_FD	3
67 #else
68 #define	CLOSE_FD	0
69 #endif
70 
71 #define	MAX_LOCKQ	1024
72 #define	MAX_DAEMONS	1024
73 #define	MAX_LOCAL	1024
74 #define	MAX_UNLOCK	32
75 #define	MAX_TIMEOUTS	3
76 #define	TIMEOUT_SECS	5
77 
78 static char program[] = "dscfglockd";
79 static int debug;
80 static int lstate;
81 static int msgtrace;
82 static FILE *debugfile = NULL;
83 
84 struct lock_req {
85 	cfglockd_t	type;	/* read or write */
86 	pid_t	pid;		/* pid of read locker or local writer */
87 	daemonaddr_t	remote;	/* remote machine requesting write lock */
88 	int		state;	/* for write locks */
89 	int32_t		order;	/* who gets priority? */
90 } lock_queue[MAX_LOCKQ];
91 
92 struct unlock_s {
93 	pid_t	pid;		/* pid of locker */
94 	uint8_t seq;		/* seq number of last lock request */
95 } unlock_buf[MAX_UNLOCK];
96 
97 int next_req;
98 int32_t order;
99 
100 #define	lock_wanted	lock_queue[0]
101 long	ticker	= 1l;
102 
103 #define	ALIVE		0x10
104 #define	READ_LOCK	0x11
105 #define	WRITE_LOCK	0x12
106 #define	UNLOCK		0x13
107 #define	GRANTED		0x14
108 
109 int next_q;
110 
111 struct {
112 	cfglockd_t	type;
113 	int		nholders;
114 	int		state;
115 	daemonaddr_t	holder;
116 	struct lockdaemon	*remote_daemon;
117 	pid_t		holding_pid[MAX_LOCAL];
118 } the_lock;
119 
120 daemonaddr_t	thishost;
121 daemonaddr_t	localhost;
122 
123 #define	STATE_CLEAR	0
124 #define	STATE_ASKED	1
125 #define	STATE_OKAYED	2
126 #define	STATE_WANTS	3
127 #define	lockdaemon_dead(ldp)	((ticker - (ldp)->timeout) > MAX_TIMEOUTS)
128 #define	CRIT_BEGIN()	sighold(SIGALRM)
129 #define	CRIT_END()	sigrelse(SIGALRM)
130 
131 #define	NORMAL_UNLOCK	0
132 #define	FORCE_UNLOCK	1
133 
134 struct lockdaemon {
135 	daemonaddr_t	host;
136 	int	up;
137 	long	timeout;
138 	int	inuse;
139 	int	state;
140 	int32_t	order;
141 } daemon_list[MAX_DAEMONS];
142 
143 unsigned short	lock_port = CFG_SERVER_PORT;
144 int	lock_soc = 0;
145 int	pf_inet = PF_INET;
146 #define	dp_addr(p)	inet_ntoa(((struct sockaddr_in *)p)->sin_addr)
147 
148 #define	MAXIFS 32
149 
150 static char *
151 lockd_type(cfglockd_t type)
152 {
153 	switch (type) {
154 	case LOCK_NOTLOCKED:	return "NotLocked";
155 	case LOCK_READ:		return "Read";
156 	case LOCK_WRITE:	return "Write";
157 	case LOCK_LOCKED:	return "Locked";
158 	case LOCK_LOCKEDBY:	return "LockedBy";
159 	case LOCK_STAT:		return "Stat";
160 	case LOCK_ACK:		return "Ack";
161 	default:		return "*unknown*";
162 	}
163 }
164 
165 static char *
166 lockd_state(int state)
167 {
168 	switch (state) {
169 	case STATE_CLEAR:	return "Clear";
170 	case STATE_ASKED:	return "Asked";
171 	case STATE_OKAYED:	return "Okayed";
172 	case STATE_WANTS:	return "Wants";
173 	default:		return "*unknown*";
174 	}
175 }
176 
177 static char *
178 lockd_msg(int message)
179 {
180 	switch (message) {
181 	case ALIVE:		return "Alive";
182 	case READ_LOCK:		return "ReadLock";
183 	case WRITE_LOCK:	return "WriteLock";
184 	case UNLOCK:		return "Unlock";
185 	case GRANTED:		return "Granted";
186 	default:		return lockd_type((cfglockd_t)message);
187 	}
188 }
189 
190 /*
191  * The following is stolen from autod_nfs.c
192  */
193 static void
194 getmyaddrs(struct ifconf *ifc)
195 {
196 	int sock;
197 	int numifs;
198 	char *buf;
199 	int family;
200 
201 	ifc->ifc_buf = NULL;
202 	ifc->ifc_len = 0;
203 
204 #ifdef AF_INET6
205 	family = AF_INET6;
206 #else
207 	family = AF_INET;
208 #endif
209 	if ((sock = socket(family, SOCK_DGRAM, 0)) < 0) {
210 #ifdef DEBUG
211 		perror("getmyaddrs(): socket");
212 #endif
213 		return;
214 	}
215 
216 	if (ioctl(sock, SIOCGIFNUM, (char *)&numifs) < 0) {
217 #ifdef DEBUG
218 		perror("getmyaddrs(): SIOCGIFNUM");
219 #endif
220 		numifs = MAXIFS;
221 	}
222 
223 	buf = (char *)malloc(numifs * sizeof (struct ifreq));
224 	if (buf == NULL) {
225 #ifdef DEBUG
226 		(void) fprintf(stderr, "getmyaddrs(): malloc failed\n");
227 #endif
228 		(void) close(sock);
229 		return;
230 	}
231 
232 	ifc->ifc_buf = buf;
233 	ifc->ifc_len = numifs * sizeof (struct ifreq);
234 
235 	if (ioctl(sock, SIOCGIFCONF, (char *)ifc) < 0) {
236 #ifdef DEBUG
237 		perror("getmyaddrs(): SIOCGIFCONF");
238 #endif
239 	}
240 
241 	(void) close(sock);
242 }
243 
244 struct ifconf *ifc;
245 
246 static int
247 cmp_addr(daemonaddr_t *a, daemonaddr_t *b)
248 {
249 	int rc;
250 	rc = memcmp(&(a->sin_addr), &(b->sin_addr), sizeof (a->sin_addr));
251 	DPF((stderr, "compare %s %hu with", dp_addr(a), a->sin_port));
252 	DPF((stderr, " %s %hu = %d\n", dp_addr(b), b->sin_port, rc));
253 	return (rc);
254 }
255 
256 static int
257 addr_is_holder(int32_t order)
258 {
259 	return ((the_lock.nholders > 0) && the_lock.remote_daemon != NULL &&
260 	    (order == the_lock.remote_daemon->order));
261 }
262 
263 static int
264 islocalhost(daemonaddr_t *host)
265 {
266 	int n;
267 	struct sockaddr_in *s1, *s2;
268 	struct ifreq *ifr;
269 	int retval = 0;
270 
271 	ifr = ifc->ifc_req;
272 	n = ifc->ifc_len / sizeof (struct ifreq);
273 	s1 = host;
274 	s2 = NULL;
275 	for (; n > 0; n--, ifr++) {
276 		if (ifr->ifr_addr.sa_family != AF_INET)
277 			continue;
278 
279 		/* LINTED pointer alignment */
280 		s2 = (struct sockaddr_in *)&ifr->ifr_addr;
281 
282 		if (memcmp((char *)&s2->sin_addr,
283 			(char *)&s1->sin_addr, sizeof (s1->sin_addr)) == 0) {
284 			retval = 1;
285 			/* it's me */
286 			break;
287 		}
288 	}
289 	return (retval);
290 }
291 
292 static void
293 send_lockmsg(int cmd, pid_t pid, daemonaddr_t *dp, uint8_t seq)
294 {
295 	struct lock_msg message_buf;
296 	int rc;
297 
298 	if (msgtrace && debugfile) {
299 		time_t t = time(0);
300 		(void) fprintf(debugfile, "%19.19s send %-9.9s to   %s\n",
301 		    ctime(&t), lockd_msg(cmd), dp_addr(dp));
302 	}
303 	DPF((stderr, "send %d to %s port %hu\n", cmd,
304 			dp_addr(dp), dp->sin_port));
305 	message_buf.message = cmd;
306 	message_buf.pid = pid;
307 	message_buf.order = order;
308 	message_buf.seq = seq;
309 	do {
310 		rc = sendto(lock_soc, &message_buf, sizeof (message_buf), 0,
311 		    (struct sockaddr *)dp, sizeof (struct sockaddr));
312 	} while (rc == -1 && errno == EINTR);
313 	if (rc == -1)
314 		spcs_log("cfglockd", NULL, "sendto rc -1 errno %d", errno);
315 }
316 
317 /*
318  * send an alive message to all configured daemons so that they can tell
319  * us if they are holding a write lock.
320  */
321 
322 static void
323 send_aliveall()
324 {
325 	struct lockdaemon *ldp;
326 	int i;
327 	for (i = 0, ldp = daemon_list; i < MAX_DAEMONS; i++, ldp++) {
328 		if (ldp->inuse == 0)
329 			break;
330 		send_lockmsg(ALIVE, (pid_t)0, &(ldp->host), 0);
331 	}
332 }
333 
334 /* find the lock daemon structure for a give daemon address */
335 
336 static struct lockdaemon *
337 find_lockdaemon(daemonaddr_t *d)
338 {
339 	struct lockdaemon *ldp;
340 	int i;
341 	for (i = 0, ldp = daemon_list; i < MAX_DAEMONS; i++, ldp++) {
342 		if (ldp->inuse == 0)
343 			break;
344 		if (cmp_addr(&(ldp->host), d) == 0)
345 			return (ldp);
346 	}
347 	return (NULL);
348 }
349 
350 /*
351  * a messge has been received from daemon, note this and if the daemon
352  * was previously dead  and we have the write lock tell it that we do.
353  */
354 
355 static void
356 daemon_alive(daemonaddr_t *daemon, int32_t order)
357 {
358 	struct lockdaemon *ldp;
359 	int i;
360 
361 	for (i = 0, ldp = daemon_list; i < MAX_DAEMONS; i++, ldp++) {
362 		if (ldp->inuse == 0)
363 			break;
364 		if (cmp_addr(&(ldp->host), daemon) == 0) {
365 			ldp->order = order;
366 			ldp->timeout = ticker;
367 			if (ldp->up == 0) {
368 				spcs_log("cfglockd", NULL,
369 				    "daemon restarted on %s\n",
370 				    dp_addr(daemon));
371 				DPF((stderr, "daemon restarted on %s\n",
372 				    dp_addr(daemon)));
373 				ldp->up = 1;
374 				goto come_up;
375 			}
376 			return;
377 		}
378 	}
379 	/* new daemon has announced itself */
380 	if (i < MAX_DAEMONS) {
381 		DPF((stderr, "new daemon on %s\n", dp_addr(daemon)));
382 		spcs_log("cfglockd", NULL,
383 		    "new daemon on %s\n", dp_addr(daemon));
384 		ldp->host = *daemon;
385 		ldp->inuse = 1;
386 		ldp->timeout = ticker;
387 		ldp->order = order;
388 	} else {
389 		/* problem, more daemons than expected */
390 		i++;
391 	}
392 come_up:
393 	if (the_lock.type == LOCK_WRITE && the_lock.remote_daemon == NULL)
394 		send_lockmsg(WRITE_LOCK, (pid_t)0, daemon, 0);
395 }
396 
397 static void
398 delete_queue_entry(struct  lock_req *req)
399 {
400 	int i;
401 
402 	for (i = (req - lock_queue); i++ < next_req; req++)
403 		*req = *(req+1);
404 	next_req--;
405 }
406 
407 static void
408 take_lock(int ackmessage)
409 {
410 	send_lockmsg(ackmessage, (pid_t)0, &lock_wanted.remote, 0);
411 	delete_queue_entry(lock_queue);
412 }
413 
414 static void
415 check_for_write_lock()
416 {
417 	struct lockdaemon *ldp;
418 	int i;
419 	int	wait = 0;
420 
421 	DPF((stderr, "check for lock\n"));
422 	if (lock_wanted.state != STATE_ASKED)
423 		return;
424 	for (i = 0, ldp = daemon_list; i < MAX_DAEMONS; i++, ldp++) {
425 		if (ldp->inuse == 0)
426 			break;
427 		if (ldp->up && ldp->state != STATE_OKAYED) {
428 			wait = 1;
429 			break;
430 		}
431 	}
432 	if (wait == 0 && lock_wanted.type == LOCK_WRITE) {
433 		the_lock.type = LOCK_WRITE;
434 		the_lock.holding_pid[0] = lock_wanted.pid;
435 		the_lock.nholders = 1;
436 		the_lock.state = STATE_CLEAR;
437 		take_lock(LOCK_LOCKED);
438 	}
439 }
440 
441 static void
442 lock_granted(daemonaddr_t *da)
443 {
444 	struct lockdaemon *ldp;
445 
446 	if ((ldp = find_lockdaemon(da)) != NULL) {
447 		/* if we already own the lock, throw the msg away */
448 		if (the_lock.remote_daemon == NULL &&
449 		    the_lock.type == LOCK_WRITE) {
450 			return;
451 		}
452 
453 		/*
454 		 * If the current lock isn't a write lock and we're not
455 		 * asking for one
456 		 * -OR-
457 		 * The current lock is a write lock and it's not owned by us
458 		 * -THEN-
459 		 * send back an unlocked message.
460 		 */
461 		if ((the_lock.type != LOCK_WRITE &&
462 		    the_lock.state != STATE_ASKED) ||
463 		    (the_lock.type == LOCK_WRITE &&
464 		    the_lock.remote_daemon != NULL)) {
465 			send_lockmsg(UNLOCK, (pid_t)0, &(ldp->host), 0);
466 			return;
467 		}
468 		ldp->state = STATE_OKAYED;
469 	}
470 	check_for_write_lock();
471 }
472 
473 static int
474 try_lock()
475 {
476 	struct lockdaemon *ldp;
477 	int i;
478 
479 	switch (the_lock.type) {
480 	case LOCK_READ:
481 		if (lock_wanted.type == LOCK_READ) {
482 			i = the_lock.nholders++;
483 			the_lock.holding_pid[i] = lock_wanted.pid;
484 			the_lock.state = STATE_CLEAR;
485 			DPF((stderr, "increment read lockers to %d\n",
486 			    the_lock.nholders));
487 			take_lock(LOCK_LOCKED);
488 			break;
489 		}
490 		/* write lock has to wait */
491 		break;
492 	case LOCK_WRITE:
493 		/* lock has to wait until write lock is cleared */
494 		break;
495 	case LOCK_NOTLOCKED:
496 		if (lock_wanted.type == LOCK_READ) {
497 			DPF((stderr, "local locker, 1 lock holder\n"));
498 			the_lock.holding_pid[0] = lock_wanted.pid;
499 			the_lock.nholders = 1;
500 			the_lock.type = LOCK_READ;
501 			the_lock.state = STATE_CLEAR;
502 			the_lock.remote_daemon = NULL;
503 			take_lock(LOCK_LOCKED);
504 			return (1);
505 		}
506 		if (islocalhost(&lock_wanted.remote)) {
507 			DPF((stderr, "local locker, take write lock\n"));
508 			/* tell everyone I'm locking */
509 			if (lock_wanted.state != STATE_ASKED) {
510 				for (i = 0, ldp = daemon_list; i < MAX_DAEMONS;
511 				    i++, ldp++) {
512 					if (ldp->inuse == 0)
513 						break;
514 					ldp->state = STATE_ASKED;
515 					send_lockmsg(WRITE_LOCK, (pid_t)0,
516 					    &(ldp->host), 0);
517 				}
518 			}
519 			lock_wanted.state = STATE_ASKED;
520 			check_for_write_lock();
521 			the_lock.remote_daemon = NULL;
522 			the_lock.state = STATE_ASKED;
523 			return (0);
524 		} else {
525 			DPF((stderr, "remote locker, take write lock\n"));
526 			the_lock.type = LOCK_WRITE;
527 			the_lock.holder = lock_wanted.remote;
528 			the_lock.nholders = 1;
529 			the_lock.remote_daemon =
530 			    find_lockdaemon(&the_lock.holder);
531 			the_lock.state = STATE_CLEAR;
532 			/* okay to remote */
533 			take_lock(GRANTED);
534 		}
535 		break;
536 	default:
537 		DPF((stderr, "weird lock type held - %d\n", the_lock.type));
538 		the_lock.type = LOCK_NOTLOCKED;
539 		break;
540 	}
541 	return (0);
542 }
543 
544 static void
545 process_queue()
546 {
547 	if (next_req < 1)
548 		return;		/* no locks queued */
549 	while (try_lock())
550 		;
551 }
552 
553 static int
554 lock_sort(const void *a, const void *b)
555 {
556 	struct lock_req *left = (struct lock_req *)a;
557 	struct lock_req *right = (struct lock_req *)b;
558 
559 	return (left->order - right->order);
560 }
561 
562 static void
563 queue_lock(cfglockd_t type, struct lock_msg *msg, daemonaddr_t *addr)
564 {
565 	int	i;
566 	struct lock_req *lrp;
567 	struct lockdaemon *ldp;
568 
569 	/* first check if new lock matches current lock */
570 	if (the_lock.type == type && addr_is_holder(msg->order)) {
571 		/* remote daemon missed locked message */
572 		send_lockmsg(GRANTED, (pid_t)0, addr, msg->seq);
573 		return;
574 	}
575 
576 	/* next search queue to check for duplicate */
577 	for (i = 0, lrp = lock_queue; i++ < next_req; lrp++) {
578 		if (lrp->type == type && lrp->pid == msg->pid &&
579 		    cmp_addr(addr, &(lrp->remote)) == 0)
580 			return;
581 
582 	}
583 
584 	/*
585 	 * It's a new lock request.  Are we in the middle of
586 	 * obtaining one for ourselves?
587 	 */
588 
589 	if (the_lock.type == LOCK_NOTLOCKED && the_lock.state == STATE_ASKED) {
590 		/* did a higher priority request just come in? */
591 		if (msg->order < order) {
592 			/* requeue our request */
593 			the_lock.state = STATE_CLEAR;
594 			lock_wanted.state = STATE_CLEAR;
595 
596 			/* let the other lockds know */
597 			for (i = 0, ldp = daemon_list; i < MAX_DAEMONS;
598 			    i++, ldp++) {
599 				if (ldp->inuse == 0)
600 					break;
601 				if (ldp->up && ldp->state == STATE_OKAYED) {
602 					send_lockmsg(UNLOCK, (pid_t)0,
603 					    &(ldp->host), 0);
604 				}
605 			}
606 		}
607 	}
608 
609 
610 	lrp = lock_queue;
611 	lrp += (next_req++);
612 	lrp->type = type;
613 	lrp->pid = msg->pid;
614 	lrp->state = STATE_CLEAR;
615 	lrp->order = msg->order;
616 	if (addr) {
617 		lrp->remote = *addr;
618 	}
619 
620 	if (next_req > 1)
621 		qsort(lock_queue, next_req, sizeof (lock_queue[0]), lock_sort);
622 
623 	if (the_lock.type != LOCK_WRITE)
624 		process_queue();
625 }
626 
627 static void
628 lock_stat()
629 {
630 	char *lt = "Unknown";
631 	struct lockdaemon *ldp;
632 	int i;
633 
634 	spcs_log("cfglockd", NULL,
635 	    "%s, Lock daemon built %s **********", program, __DATE__);
636 	switch (the_lock.type) {
637 	case LOCK_NOTLOCKED:
638 		lt = "not locked";
639 		break;
640 	case LOCK_READ:
641 		lt = "read locked";
642 		break;
643 	case LOCK_WRITE:
644 		lt = "write locked";
645 		break;
646 	}
647 	spcs_log("cfglockd", NULL, "Lock is %s (%d)", lt, the_lock.type);
648 	spcs_log("cfglockd", NULL, "There are %d holders of the lock",
649 	    the_lock.nholders);
650 	if (the_lock.nholders > 0) {
651 		for (i = 0; i < the_lock.nholders; i++)
652 			spcs_log("cfglockd", NULL, "holding_pid[%d] = %6d", i,
653 			    the_lock.holding_pid[i]);
654 	}
655 	spcs_log("cfglockd", NULL, "holder daemon was %s port %hu, remote %x",
656 	    dp_addr(&the_lock.holder), the_lock.holder.sin_port,
657 	    the_lock.remote_daemon);
658 	spcs_log("cfglockd", NULL, "Lock queue, %d requests", next_req);
659 	for (i = 0; i < next_req; i++) {
660 		spcs_log("cfglockd", NULL, "request %d type %d order %d", i,
661 		    lock_queue[i].type, lock_queue[i].order);
662 		spcs_log("cfglockd", NULL, "  client %s port %hu, pid %d",
663 		    dp_addr(&lock_queue[i].remote),
664 		    lock_queue[i].remote.sin_port, lock_queue[i].pid);
665 	}
666 	spcs_log("cfglockd", NULL, "Daemon list");
667 
668 	for (i = 0, ldp = daemon_list; i < MAX_DAEMONS; i++, ldp++) {
669 		if (ldp->inuse == 0)
670 			break;
671 		spcs_log("cfglockd", NULL, "daemon %d, %s port %hu", i,
672 		    dp_addr(&ldp->host), ldp->host.sin_port);
673 		spcs_log("cfglockd", NULL,
674 		    "  up %d timeout %ld missed %d state %d\n", ldp->up,
675 		    ldp->timeout, ticker - ldp->timeout, ldp->state);
676 	}
677 }
678 
679 static int
680 is_duplicate(cfglockd_t type, pid_t pid, uint8_t seq)
681 {
682 	struct unlock_s *bufp;
683 	int i;
684 
685 	if (!pid) {
686 		return (0);
687 	}
688 
689 	for (i = 0, bufp = unlock_buf; bufp->pid && i < MAX_UNLOCK;
690 	    i++, bufp++) {
691 		if (bufp->pid == pid && bufp->seq == seq) {
692 			/* throw message away */
693 #ifdef DEBUG
694 			spcs_log("cfglockd", NULL,
695 			    "duplicate '%d' request received from %d",
696 			    type, pid);
697 #endif
698 			return (1);
699 		}
700 	}
701 
702 	/* add it to the list */
703 	bcopy(unlock_buf, &unlock_buf[ 1 ],
704 	    sizeof (unlock_buf) - sizeof (struct unlock_s));
705 	(*unlock_buf).pid = pid;
706 	(*unlock_buf).seq = seq;
707 
708 	return (0);
709 }
710 
711 static void
712 local_lock(cfglockd_t type, struct lock_msg *msg, daemonaddr_t *client)
713 {
714 	if (is_duplicate(type, msg->pid, msg->seq)) {
715 		if (the_lock.remote_daemon == NULL &&
716 		    (the_lock.type == LOCK_WRITE ||
717 		    the_lock.type == LOCK_READ) &&
718 		    the_lock.holding_pid[0] == msg->pid) {
719 			send_lockmsg(LOCK_LOCKED, (pid_t)0, client, msg->seq);
720 		}
721 	} else {
722 		queue_lock(type, msg, client);
723 	}
724 }
725 
726 static void
727 remote_lock(struct sockaddr_in *remote, struct lock_msg *msg)
728 {
729 	/* make sure remote knows we are alive */
730 	send_lockmsg(ALIVE, (pid_t)0, remote, 0);
731 
732 	/* clear out pid as it is meaningless on this node */
733 	msg->pid = (pid_t)0;
734 
735 	queue_lock(LOCK_WRITE, msg, (daemonaddr_t *)remote);
736 }
737 
738 static void
739 unqueue_lock(daemonaddr_t *d, pid_t pid)
740 {
741 	int	i;
742 	struct lock_req *lrp, *xrp;
743 	int diff;
744 
745 	/* search queue to delete ungranted locks */
746 	for (i = 0, xrp = lrp = lock_queue; i++ < next_req; lrp++) {
747 		*xrp = *lrp;
748 		diff = 0;
749 		if (pid != (pid_t)0 && lrp->pid != pid)
750 			diff = 1;
751 		if (d != NULL && cmp_addr(d, &(lrp->remote)) != 0)
752 			diff = 1;
753 		if (!diff)
754 			continue;
755 
756 		xrp++;
757 	}
758 	next_req = xrp - lock_queue;
759 }
760 
761 static void
762 xxunlock()
763 {
764 	DPF((stderr, "** UNLOCK **\n"));
765 	the_lock.remote_daemon = NULL;
766 	the_lock.type = LOCK_NOTLOCKED;
767 	the_lock.nholders = 0;
768 	the_lock.state = STATE_CLEAR;
769 	process_queue();
770 }
771 
772 
773 static void
774 local_unlock(pid_t pid, uint8_t seq, int method)
775 {
776 	struct lockdaemon *ldp;
777 	int i;
778 
779 	if (method == NORMAL_UNLOCK && is_duplicate(LOCK_NOTLOCKED, pid, seq)) {
780 		return;
781 	}
782 
783 	if (the_lock.type == LOCK_READ) {
784 		/* delete reference to pid of reading process */
785 		for (i = 0; i < the_lock.nholders; i++) {
786 			if (the_lock.holding_pid[i] == pid) {
787 				DPF((stderr, "decrement lockers from %d\n",
788 				    the_lock.nholders));
789 				--the_lock.nholders;
790 				break;
791 			}
792 		}
793 		for (; i < the_lock.nholders; i++) {
794 			the_lock.holding_pid[i] = the_lock.holding_pid[i+1];
795 		}
796 		if (the_lock.nholders > 0)
797 			return;
798 	} else {
799 		/* LOCK_WRITE */
800 		if (pid != the_lock.holding_pid[0])
801 			return;
802 		the_lock.holding_pid[0] = (pid_t)0;
803 		for (i = 0, ldp = daemon_list; i < MAX_DAEMONS; i++, ldp++) {
804 			if (ldp->inuse == 0)
805 				break;
806 			if (ldp->up)
807 				send_lockmsg(UNLOCK, (pid_t)0, &(ldp->host), 0);
808 		}
809 	}
810 	xxunlock();
811 }
812 
813 static void
814 remote_unlock(int32_t order, daemonaddr_t *d)
815 {
816 	int	i;
817 	struct lock_req *lrp;
818 
819 	DPF((stderr, "remote unlock from %s ", dp_addr(d)));
820 	DPF((stderr, "when %s holds lock\n", dp_addr(&the_lock.holder)));
821 
822 	/* search queue to check for ungranted lock */
823 	for (i = 0, lrp = lock_queue; i++ < next_req; lrp++) {
824 		if (lrp->type == LOCK_WRITE &&
825 		    cmp_addr(d, &(lrp->remote)) == 0) {
826 			delete_queue_entry(lrp);
827 			return;
828 		}
829 
830 	}
831 	if (addr_is_holder(order)) {
832 		xxunlock();
833 	}
834 }
835 
836 static void
837 lockedby(daemonaddr_t *d, uint8_t seq)
838 {
839 	DPF((stderr, "lockby enquiry from %s ", dp_addr(d)));
840 	switch (the_lock.type) {
841 	case LOCK_NOTLOCKED:
842 		send_lockmsg(LOCK_NOTLOCKED, (pid_t)0, d, seq);
843 		break;
844 	case LOCK_READ:
845 		send_lockmsg(LOCK_READ, the_lock.holding_pid[0], d, seq);
846 		break;
847 	case LOCK_WRITE:
848 		send_lockmsg(LOCK_WRITE, the_lock.holding_pid[0], d, seq);
849 		break;
850 	}
851 }
852 
853 /* ARGSUSED */
854 static void
855 keepalive(int signo)
856 {
857 	int i;
858 	struct lock_req *locker;
859 	struct lockdaemon *ldp;
860 
861 	DPF((stderr, "keepalive...\n"));
862 	ticker++;
863 
864 	/*
865 	 * tell any other daemon that has a lock request in our queue that
866 	 * this daemon is still alive.
867 	 */
868 
869 	for (i = 0, locker = lock_queue; i < next_req; i++, locker++) {
870 		if (locker->pid == 0)	/* remote lock request */
871 			send_lockmsg(ALIVE, (pid_t)0, &(locker->remote), 0);
872 	}
873 
874 	/*
875 	 * if a remote daemon holds the lock, check it is still alive and
876 	 * if the remote daemon is sent it a grant message in case the
877 	 * remote daemon missed our original grant.
878 	 */
879 
880 	if (the_lock.remote_daemon) {
881 		if (lockdaemon_dead(the_lock.remote_daemon)) {
882 			DPF((stderr, "lock owner died\n"));
883 			the_lock.remote_daemon->up = 0;
884 			xxunlock();
885 		} else {
886 			send_lockmsg(GRANTED, (pid_t)0, &the_lock.holder, 0);
887 		}
888 	}
889 
890 	/*
891 	 * check for response from daemons preventing this daemon
892 	 * from taking a write lock by not sending a grant message.
893 	 * if the remote daemon is alive send another lock request,
894 	 * otherwise mark it as dead.
895 	 * send alive message to any live remote daemons if this
896 	 * daemon has the write lock.
897 	 */
898 	if (lstate) {
899 		(void) printf("\nlock: %s\n", lockd_type(the_lock.type));
900 		(void) printf("    no. holders: %d\n", the_lock.nholders);
901 		(void) printf("    hold addr  : %s\n", the_lock.remote_daemon?
902 		    dp_addr(the_lock.remote_daemon): "0.0.0.0");
903 		(void) printf("    holding pid:");
904 		for (i = 0; i < the_lock.nholders; i++) {
905 			(void) printf(" %ld", the_lock.holding_pid[ i ]);
906 		}
907 		(void) printf("\n");
908 	}
909 	for (i = 0, ldp = daemon_list; i < MAX_DAEMONS; i++, ldp++) {
910 		if (ldp->inuse == 0)
911 			break;
912 
913 		if (lstate) {
914 			(void) printf("%-15.15s ", dp_addr(&ldp->host));
915 			(void) printf("%-4.4s ", ldp->up? "up" : "down");
916 			(void) printf("%5ld ", ldp->timeout);
917 			(void) printf("%-10.10s ", lockd_state(ldp->state));
918 			(void) printf("%6d\n", ldp->order);
919 		}
920 
921 		if (ldp->state == STATE_ASKED) {
922 			if (lockdaemon_dead(ldp)) {
923 				ldp->up = 0;
924 				ldp->state = STATE_CLEAR;
925 				continue;
926 			}
927 			send_lockmsg(WRITE_LOCK, (pid_t)0, &(ldp->host), 0);
928 			continue;
929 		}
930 		if (the_lock.type == LOCK_WRITE &&
931 		    the_lock.remote_daemon == NULL)
932 			send_lockmsg(ALIVE, (pid_t)0, &(ldp->host), 0);
933 	}
934 }
935 
936 static void
937 dispatch(struct lock_msg *mp, daemonaddr_t *host)
938 {
939 	int message = mp->message;
940 	int localhost;
941 
942 	localhost = islocalhost(host);
943 	if (msgtrace && debugfile) {
944 		time_t t = time(0);
945 		if (localhost) {
946 			(void) fprintf(debugfile,
947 			    "%19.19s recv %-9.9s from %s (%ld)\n", ctime(&t),
948 			    lockd_msg(message), dp_addr(host), mp->pid);
949 		} else {
950 			(void) fprintf(debugfile,
951 			    "%19.19s recv %-9.9s from %s order %d (%ld)\n",
952 			    ctime(&t), lockd_msg(message), dp_addr(host),
953 			    mp->order, mp->pid);
954 		}
955 	}
956 	DPF((stderr, "received message %d\n", message));
957 	DPF((stderr, "from %s port %hu\n", dp_addr(host), host->sin_port));
958 	if (!localhost)
959 		daemon_alive(host, mp->order);
960 	else
961 		mp->order = order;
962 	switch (message) {
963 	case ALIVE:
964 		DPF((stderr, "received ALIVE %s\n", dp_addr(host)));
965 		/* do nothing, general "not localhost" code above does this */
966 		break;
967 	case UNLOCK:
968 		DPF((stderr, "received UNLOCK\n"));
969 		remote_unlock(mp->order, host);
970 		break;
971 	case GRANTED:
972 		DPF((stderr, "received GRANTED\n"));
973 		lock_granted(host);
974 		break;
975 	case WRITE_LOCK:
976 		DPF((stderr, "received WRITE_LOCK\n"));
977 		assert(!localhost);
978 		remote_lock(host, mp);
979 		break;
980 	case READ_LOCK:
981 	case LOCK_READ:
982 		DPF((stderr, "received READ_LOCK\n"));
983 		assert(localhost);
984 		local_lock(LOCK_READ, mp, host);
985 		break;
986 	case LOCK_WRITE:
987 		DPF((stderr, "received LOCK_WRITE\n"));
988 		assert(localhost);
989 		local_lock(LOCK_WRITE, mp, host);
990 		break;
991 	case LOCK_NOTLOCKED:
992 		DPF((stderr, "received LOCK_NOTLOCKED\n"));
993 		send_lockmsg(LOCK_ACK, (pid_t)0, host, mp->seq);
994 		if (the_lock.type != LOCK_NOTLOCKED) {
995 			local_unlock(mp->pid, mp->seq, NORMAL_UNLOCK);
996 		}
997 		break;
998 	case LOCK_LOCKEDBY:
999 		lockedby(host, mp->seq);
1000 		break;
1001 	case LOCK_STAT:
1002 		lock_stat();
1003 		break;
1004 	case LOCK_ACK:
1005 		/* throw message away -- this is an error to receive */
1006 		break;
1007 	}
1008 }
1009 
1010 /*
1011  * unqueue any locks asked for by pid and unlock any locks held by pid.
1012  */
1013 
1014 static void
1015 purge_pid(pid_t pid)
1016 {
1017 	DPF((stderr, "purge locks for %ld\n", pid));
1018 	unqueue_lock(NULL, pid);
1019 	if (the_lock.type != LOCK_NOTLOCKED)
1020 		local_unlock(pid, 0, FORCE_UNLOCK);
1021 }
1022 
1023 /*
1024  * Check for exit or exec of client processes.
1025  * The lock protecting the processes pid in the lockfile will
1026  * be removed by the kernel when a client exits or execs.
1027  */
1028 
1029 static void
1030 check_for_dead()
1031 {
1032 	int i, x;
1033 	pid_t pid;
1034 
1035 	for (i = 0; (x = cfg_filelock(i, 0)) != CFG_LF_EOF; i++) {
1036 		if (x == CFG_LF_AGAIN)
1037 			continue; /* can't take lock, must be still alive */
1038 		cfg_readpid(i, &pid);
1039 		cfg_writepid(i, (pid_t)0);
1040 		cfg_fileunlock(i);
1041 		if (pid != (pid_t)0)
1042 			purge_pid(pid);
1043 	}
1044 }
1045 
1046 static void
1047 build_daemon_list(char *cf_file, int exe)
1048 {
1049 	FILE *fp;
1050 	char	host[1024];
1051 	int	port;
1052 	int	i;
1053 	struct	hostent *hp;
1054 	struct lockdaemon *ldp;
1055 
1056 	if ((hp = gethostbyname("localhost")) == NULL) {
1057 		(void) fprintf(stderr, "%s: Can't find hostent for %s\n",
1058 		    program, "localhost");
1059 		spcs_log("cfglockd", NULL, "couldn't find localhost");
1060 		exit(1);
1061 	}
1062 
1063 	(void) memcpy(&(localhost.sin_addr.s_addr), *(hp->h_addr_list),
1064 			sizeof (localhost.sin_addr));
1065 	if (cf_file == NULL) {
1066 		(void) endhostent();
1067 		return;
1068 	}
1069 	if (exe) {
1070 		if ((fp = popen(cf_file, "r")) == NULL) {
1071 			perror(cf_file);
1072 			(void) fprintf(stderr,
1073 			    "%s: Can't open config program\n", program);
1074 			spcs_log("cfglockd", NULL, "couldn't read config");
1075 			exit(1);
1076 		}
1077 	} else {
1078 		if ((fp = fopen(cf_file, "r")) == NULL) {
1079 			perror(cf_file);
1080 			(void) fprintf(stderr, "%s: Can't open config file\n",
1081 			    program);
1082 			spcs_log("cfglockd", NULL, "couldn't read config");
1083 			exit(1);
1084 		}
1085 	}
1086 	ldp = daemon_list;
1087 	while ((i = fscanf(fp, "%s %d\n", host, &port)) != EOF) {
1088 		if (host[0] == '#')	/* line starting with # are comments */
1089 			continue;
1090 		if (i == 1) {
1091 			port = lock_port;
1092 		} else {
1093 			if (strcmp(host, "localhost") == 0) {
1094 				lock_port = port;
1095 				continue;
1096 			}
1097 		}
1098 
1099 		if ((hp = gethostbyname(host)) == NULL) {
1100 			(void) fprintf(stderr,
1101 			    "%s: Can't find hostent for %s\n", program, host);
1102 			continue;
1103 		}
1104 
1105 		(void) memcpy(&(ldp->host.sin_addr.s_addr), *(hp->h_addr_list),
1106 		    sizeof (ldp->host.sin_addr));
1107 		DPF((stderr, "daemon: %s\t%s\n",
1108 				inet_ntoa(ldp->host.sin_addr), hp->h_name));
1109 		if (islocalhost(&(ldp->host))) {
1110 			DPF((stderr, "is an alias for this host, skipping\n"));
1111 			continue;
1112 		}
1113 		ldp->host.sin_port = htons((short)port);
1114 		ldp->host.sin_family = hp->h_addrtype;
1115 		ldp->inuse = 1;
1116 		ldp->up = 1;
1117 		ldp++;
1118 	}
1119 	if (exe)
1120 		(void) pclose(fp);
1121 	else
1122 		(void) fclose(fp);
1123 	(void) endhostent();
1124 }
1125 
1126 static void
1127 usage()
1128 {
1129 	(void) fprintf(stderr,
1130 	    gettext("usage: %s [-d] [-f file]|[-e program]\n"), program);
1131 	exit(1);
1132 }
1133 
1134 static void
1135 unexpected(int sig)
1136 {
1137 	spcs_log("cfglockd", NULL, "pid %d unexpected signal %d, ignoring",
1138 	    getpid(), sig);
1139 }
1140 
1141 static void
1142 term(int sig)
1143 {
1144 	(void) unlink(CFG_PIDFILE);
1145 	spcs_log("cfglockd", NULL, "pid %d terminate on signal %d", getpid(),
1146 	    sig);
1147 	exit(0);
1148 }
1149 
1150 static void
1151 init(int argc, char *argv[])
1152 {
1153 #if defined(_SunOS_5_6) || defined(_SunOS_5_7) || defined(_SunOS_5_8)
1154 	struct rlimit rl;
1155 #endif
1156 	int	c, i, x;
1157 	int	rc;
1158 	char	*cp = NULL;
1159 	struct	itimerval	tv;
1160 	struct	timeval		tp;
1161 	socklen_t len = sizeof (thishost);
1162 	int	exe = 0;
1163 	pid_t	pid;
1164 	FILE	*fp;
1165 
1166 	lstate = (getenv("LOCKD_STATE") != NULL);
1167 	msgtrace = (getenv("LOCKD_MSG") != NULL);
1168 
1169 	/*
1170 	 * Fork off a child that becomes the daemon.
1171 	 */
1172 
1173 #ifndef TTY_MESSAGES
1174 	if ((rc = fork()) > 0)
1175 		exit(0);
1176 	else if (rc < 0) {
1177 		spcs_log("cfglockd", NULL, "can't fork %d", errno);
1178 		(void) fprintf(stderr, gettext("dscfglockd: cannot fork: %s\n"),
1179 		    strerror(errno));
1180 		exit(1);
1181 	}
1182 #endif
1183 
1184 	/*
1185 	 * In child - become daemon.
1186 	 */
1187 
1188 #if !defined(_SunOS_5_6) && !defined(_SunOS_5_7) && !defined(_SunOS_5_8)
1189 	/* use closefrom(3C) from PSARC/2000/193 when possible */
1190 	closefrom(CLOSE_FD);
1191 #else
1192 	(void) getrlimit(RLIMIT_NOFILE, &rl);
1193 	for (i = CLOSE_FD; i < rl.rlim_max; i++)
1194 		(void) close(i);
1195 #endif
1196 
1197 #ifdef DEBUG
1198 #ifndef	TTY_MESSAGES
1199 	(void) open("/dev/console", O_WRONLY|O_APPEND);
1200 	(void) dup(0);
1201 	(void) dup(0);
1202 #endif
1203 #endif
1204 	(void) close(0);
1205 
1206 	if (msgtrace || lstate) {
1207 		debugfile = fopen("/var/tmp/dscfglockd.out", "a");
1208 		if (debugfile) {
1209 			time_t t = time(0);
1210 			setbuf(debugfile, (char *)0);
1211 			(void) fprintf(debugfile, "%19.19s dscfglockd start\n",
1212 			    ctime(&t));
1213 		}
1214 	}
1215 
1216 	(void) setpgrp();
1217 	spcs_log("cfglockd", NULL, "new lock daemon, pid %d", getpid());
1218 
1219 	/*
1220 	 * Catch as unexpected all signals apart from SIGTERM.
1221 	 */
1222 
1223 	for (i = 1; i < _sys_nsig; i++)
1224 		(void) sigset(i, unexpected);
1225 	(void) sigset(SIGTERM, term);
1226 
1227 	for (i = 0; (c = getopt(argc, argv, "df:e:")) != EOF; i++) {
1228 		switch (c) {
1229 		case 'd':
1230 			debug = 1;
1231 			break;
1232 		case 'e':
1233 			exe = 1;
1234 			if (cp) {
1235 				usage();
1236 			}
1237 			cp = optarg;
1238 			break;
1239 		case 'f':
1240 			if (cp) {
1241 				usage();
1242 			}
1243 			cp = optarg;
1244 			break;
1245 		default:
1246 			usage();
1247 			break;
1248 		}
1249 	}
1250 
1251 	ifc = (struct ifconf *)malloc(sizeof (struct ifconf));
1252 	if (ifc == NULL) {
1253 		perror(CFG_PIDFILE);
1254 		DPF((stderr, "Can't open pid file\n"));
1255 		exit(1);
1256 	}
1257 	(void) memset((char *)ifc, 0, sizeof (struct ifconf));
1258 	getmyaddrs(ifc);
1259 
1260 	/*
1261 	 * if (lockdaemonalive()) {
1262 	 *	(void) fprintf(stderr, "%s: %s\n", program,
1263 	 *		gettext("There is already a live lockdaemon"));
1264 	 *	exit(1);
1265 	 * }
1266 	 */
1267 	if ((fp = fopen(CFG_PIDFILE, "w")) == NULL) {
1268 		perror(CFG_PIDFILE);
1269 		DPF((stderr, "Can't open pid file\n"));
1270 		exit(1);
1271 	}
1272 	(void) fprintf(fp, "%ld\n", getpid());
1273 	(void) fclose(fp);
1274 
1275 	/* order should be set to node number within cluster */
1276 	order = cfg_iscluster();
1277 	cfg_lfinit();
1278 
1279 	if (!order) {
1280 		(void) gettimeofday(&tp, NULL);
1281 		srand48(tp.tv_usec);
1282 		order = lrand48();
1283 		if (debugfile) {
1284 			(void) fprintf(debugfile, "WARNING: order number "
1285 			    "is 0 -- changing randomly to %d\n", order);
1286 		}
1287 	}
1288 	c = 0;
1289 	for (i = 0; (x = cfg_filelock(i, 0)) != CFG_LF_EOF; i++) {
1290 		if (x == CFG_LF_AGAIN) {
1291 			cfg_readpid(i, &pid);
1292 			if (c++ == 0)
1293 				spcs_log("cfglockd", NULL,
1294 				    "init .dscfg.lck slot %d pid %d locked",
1295 				    i, pid);
1296 			DPF((stderr, "client process %ld still alive\n", pid));
1297 			continue; /* can't take lock, must be still alive */
1298 		}
1299 		cfg_writepid(i, 0);
1300 		cfg_fileunlock(i);
1301 	}
1302 
1303 	tv.it_interval.tv_sec = TIMEOUT_SECS;
1304 	tv.it_interval.tv_usec = 0;
1305 	tv.it_value = tv.it_interval;
1306 
1307 	bzero(unlock_buf, sizeof (unlock_buf));
1308 	next_q = 0;
1309 	build_daemon_list(cp, exe);
1310 	if ((lock_soc = socket(pf_inet, SOCK_DGRAM, 0)) < 0) {
1311 		(void) fprintf(stderr, "%s: %s\n", program,
1312 		    gettext("failed to create socket"));
1313 		perror("socket");
1314 		spcs_log("cfglockd", NULL, "couldn't create socket");
1315 		exit(1);
1316 	}
1317 	thishost.sin_family = AF_INET;
1318 	thishost.sin_addr.s_addr = INADDR_ANY;
1319 	thishost.sin_port = htons(lock_port);
1320 	rc = bind(lock_soc, (struct sockaddr *)&thishost, sizeof (thishost));
1321 	if (rc < 0) {
1322 		perror("bind");
1323 		spcs_log("cfglockd", NULL, "couldn't bind");
1324 		exit(1);
1325 	}
1326 	if (getsockname(lock_soc, (struct sockaddr *)&thishost, &len) < 0)
1327 		perror("getsockname");
1328 	send_aliveall();
1329 	sigset(SIGALRM, keepalive);
1330 	(void) setitimer(ITIMER_REAL, &tv, NULL);
1331 	/*
1332 	 * wait 2 time outs before allowing a lock to find if someone else
1333 	 * currently has the lock.
1334 	 */
1335 }
1336 
1337 #ifdef lint
1338 int
1339 lintmain(int argc, char *argv[])
1340 #else
1341 int
1342 main(int argc, char *argv[])
1343 #endif
1344 {
1345 	struct lock_msg message_buf;
1346 	daemonaddr_t from;
1347 	int addrlen;
1348 	int rc;
1349 	int x = 1;		/* kludge to stop warnings from compiler */
1350 
1351 	init(argc, argv);
1352 	CRIT_BEGIN();
1353 	while (x) {
1354 		CRIT_END();
1355 		addrlen = sizeof (from);
1356 		DPF((stderr, "begin recvfrom\n"));
1357 		rc = recvfrom(lock_soc, &message_buf, sizeof (message_buf),
1358 		    0, (struct sockaddr *)&from, &addrlen);
1359 		DPF((stderr, "end recvfrom rc = %d\n", rc));
1360 		CRIT_BEGIN();
1361 		if (rc == sizeof (message_buf))
1362 			dispatch(&message_buf, &from);
1363 		else
1364 			check_for_write_lock();
1365 
1366 		/* if we own the lock, check to see if the process died */
1367 		if (the_lock.type != LOCK_NOTLOCKED &&
1368 		    the_lock.remote_daemon == NULL)
1369 			check_for_dead();
1370 	}
1371 	CRIT_END();
1372 	return (0);
1373 }
1374