xref: /dflybsd-src/usr.sbin/rpc.lockd/lockd_lock.c (revision 29357d577416c492fed694332fb5cc1e044b7ab4)
1ce0e08e2SPeter Avalos /*
2ce0e08e2SPeter Avalos  * Copyright (c) 2000 Manuel Bouyer.
3ce0e08e2SPeter Avalos  *
4ce0e08e2SPeter Avalos  * Redistribution and use in source and binary forms, with or without
5ce0e08e2SPeter Avalos  * modification, are permitted provided that the following conditions
6ce0e08e2SPeter Avalos  * are met:
7ce0e08e2SPeter Avalos  * 1. Redistributions of source code must retain the above copyright
8ce0e08e2SPeter Avalos  *    notice, this list of conditions and the following disclaimer.
9ce0e08e2SPeter Avalos  * 2. Redistributions in binary form must reproduce the above copyright
10ce0e08e2SPeter Avalos  *    notice, this list of conditions and the following disclaimer in the
11ce0e08e2SPeter Avalos  *    documentation and/or other materials provided with the distribution.
12dc71b7abSJustin C. Sherrill  * 3. Neither the name of the University nor the names of its contributors
13ce0e08e2SPeter Avalos  *    may be used to endorse or promote products derived from this software
14ce0e08e2SPeter Avalos  *    without specific prior written permission.
15ce0e08e2SPeter Avalos  *
16ce0e08e2SPeter Avalos  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
17ce0e08e2SPeter Avalos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18ce0e08e2SPeter Avalos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19ce0e08e2SPeter Avalos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
20ce0e08e2SPeter Avalos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21ce0e08e2SPeter Avalos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22ce0e08e2SPeter Avalos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23ce0e08e2SPeter Avalos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24ce0e08e2SPeter Avalos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25ce0e08e2SPeter Avalos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26ce0e08e2SPeter Avalos  * SUCH DAMAGE.
27ce0e08e2SPeter Avalos  *
28ce0e08e2SPeter Avalos  * $NetBSD: lockd_lock.c,v 1.5 2000/11/21 03:47:41 enami Exp $
29ce0e08e2SPeter Avalos  * $FreeBSD: src/usr.sbin/rpc.lockd/lockd_lock.c,v 1.1 2001/03/19 12:50:09 alfred Exp $
30ce0e08e2SPeter Avalos  */
31ce0e08e2SPeter Avalos 
32ce0e08e2SPeter Avalos #include <stdio.h>
33ce0e08e2SPeter Avalos #include <stdlib.h>
34ce0e08e2SPeter Avalos #include <unistd.h>
35ce0e08e2SPeter Avalos #include <fcntl.h>
36ce0e08e2SPeter Avalos #include <syslog.h>
37ce0e08e2SPeter Avalos #include <errno.h>
38ce0e08e2SPeter Avalos #include <string.h>
39ce0e08e2SPeter Avalos #include <signal.h>
40ce0e08e2SPeter Avalos #include <rpc/rpc.h>
41ce0e08e2SPeter Avalos #include <sys/types.h>
42ce0e08e2SPeter Avalos #include <sys/stat.h>
43ce0e08e2SPeter Avalos #include <sys/socket.h>
44ce0e08e2SPeter Avalos #include <sys/queue.h>
45ce0e08e2SPeter Avalos #include <sys/param.h>
46ce0e08e2SPeter Avalos #include <sys/mount.h>
47ce0e08e2SPeter Avalos #include <sys/wait.h>
48ce0e08e2SPeter Avalos #include <rpcsvc/sm_inter.h>
49ce0e08e2SPeter Avalos #include <rpcsvc/nlm_prot.h>
50ce0e08e2SPeter Avalos #include "lockd_lock.h"
51ce0e08e2SPeter Avalos #include "lockd.h"
52ce0e08e2SPeter Avalos 
53ce0e08e2SPeter Avalos /* A set of utilities for managing file locking */
54ce0e08e2SPeter Avalos LIST_HEAD(lcklst_head, file_lock);
55ce0e08e2SPeter Avalos struct lcklst_head lcklst_head = LIST_HEAD_INITIALIZER(lcklst_head);
56ce0e08e2SPeter Avalos 
57ce0e08e2SPeter Avalos /* struct describing a lock */
58ce0e08e2SPeter Avalos struct file_lock {
59ce0e08e2SPeter Avalos 	LIST_ENTRY(file_lock) lcklst;
60ce0e08e2SPeter Avalos 	fhandle_t filehandle; /* NFS filehandle */
61ce0e08e2SPeter Avalos 	struct sockaddr *addr;
62ce0e08e2SPeter Avalos 	struct nlm4_holder client; /* lock holder */
63ce0e08e2SPeter Avalos 	netobj client_cookie; /* cookie sent by the client */
64ce0e08e2SPeter Avalos 	char client_name[128];
65ce0e08e2SPeter Avalos 	int nsm_status; /* status from the remote lock manager */
66ce0e08e2SPeter Avalos 	int status; /* lock status, see below */
67ce0e08e2SPeter Avalos 	int flags; /* lock flags, see lockd_lock.h */
68ce0e08e2SPeter Avalos 	pid_t locker; /* pid of the child process trying to get the lock */
69ce0e08e2SPeter Avalos 	int fd;	/* file descriptor for this lock */
70ce0e08e2SPeter Avalos };
71ce0e08e2SPeter Avalos 
72ce0e08e2SPeter Avalos /* lock status */
73ce0e08e2SPeter Avalos #define LKST_LOCKED	1 /* lock is locked */
74ce0e08e2SPeter Avalos #define LKST_WAITING	2 /* file is already locked by another host */
7524c80b2bSSascha Wildner #define LKST_PROCESSING	3 /* child is trying to acquire the lock */
76ce0e08e2SPeter Avalos #define LKST_DYING	4 /* must dies when we get news from the child */
77ce0e08e2SPeter Avalos 
78ce0e08e2SPeter Avalos void		lfree(struct file_lock *);
7921eb4b7eSSascha Wildner void		sigchild_handler(int);
80ce0e08e2SPeter Avalos enum nlm_stats	do_lock(struct file_lock *, int);
81ce0e08e2SPeter Avalos enum nlm_stats	do_unlock(struct file_lock *);
82ce0e08e2SPeter Avalos void		send_granted(struct file_lock *, int);
83ce0e08e2SPeter Avalos void		siglock(void);
84ce0e08e2SPeter Avalos void		sigunlock(void);
85ce0e08e2SPeter Avalos 
86ce0e08e2SPeter Avalos /* list of hosts we monitor */
87ce0e08e2SPeter Avalos LIST_HEAD(hostlst_head, host);
88ce0e08e2SPeter Avalos struct hostlst_head hostlst_head = LIST_HEAD_INITIALIZER(hostlst_head);
89ce0e08e2SPeter Avalos 
90ce0e08e2SPeter Avalos /* struct describing a lock */
91ce0e08e2SPeter Avalos struct host {
92ce0e08e2SPeter Avalos 	LIST_ENTRY(host) hostlst;
93ce0e08e2SPeter Avalos 	char name[SM_MAXSTRLEN];
94ce0e08e2SPeter Avalos 	int refcnt;
95ce0e08e2SPeter Avalos };
96ce0e08e2SPeter Avalos 
97ce0e08e2SPeter Avalos void	do_mon(char *);
98ce0e08e2SPeter Avalos 
99ce0e08e2SPeter Avalos /*
100ce0e08e2SPeter Avalos  * testlock(): inform the caller if the requested lock would be granted or not
101ce0e08e2SPeter Avalos  * returns NULL if lock would granted, or pointer to the current nlm4_holder
102ce0e08e2SPeter Avalos  * otherwise.
103ce0e08e2SPeter Avalos  */
104ce0e08e2SPeter Avalos 
105ce0e08e2SPeter Avalos struct nlm4_holder *
testlock(struct nlm4_lock * lock,int flags)106ce0e08e2SPeter Avalos testlock(struct nlm4_lock *lock, int flags)
107ce0e08e2SPeter Avalos {
108ce0e08e2SPeter Avalos 	struct file_lock *fl;
109ce0e08e2SPeter Avalos 	fhandle_t filehandle;
110ce0e08e2SPeter Avalos 
111ce0e08e2SPeter Avalos 	/* convert lock to a local filehandle */
112ce0e08e2SPeter Avalos 	memcpy(&filehandle, lock->fh.n_bytes, sizeof(filehandle));
113ce0e08e2SPeter Avalos 
114ce0e08e2SPeter Avalos 	siglock();
115ce0e08e2SPeter Avalos 	/* search through the list for lock holder */
116ce0e08e2SPeter Avalos 	for (fl = LIST_FIRST(&lcklst_head); fl != NULL;
117ce0e08e2SPeter Avalos 	    fl = LIST_NEXT(fl, lcklst)) {
118ce0e08e2SPeter Avalos 		if (fl->status != LKST_LOCKED)
119ce0e08e2SPeter Avalos 			continue;
120ce0e08e2SPeter Avalos 		if (memcmp(&fl->filehandle, &filehandle, sizeof(filehandle)))
121ce0e08e2SPeter Avalos 			continue;
122ce0e08e2SPeter Avalos 		/* got it ! */
123ce0e08e2SPeter Avalos 		syslog(LOG_DEBUG, "test for %s: found lock held by %s",
124ce0e08e2SPeter Avalos 		    lock->caller_name, fl->client_name);
125ce0e08e2SPeter Avalos 		sigunlock();
126ce0e08e2SPeter Avalos 		return (&fl->client);
127ce0e08e2SPeter Avalos 	}
128ce0e08e2SPeter Avalos 	/* not found */
129ce0e08e2SPeter Avalos 	sigunlock();
130ce0e08e2SPeter Avalos 	syslog(LOG_DEBUG, "test for %s: no lock found", lock->caller_name);
131ce0e08e2SPeter Avalos 	return NULL;
132ce0e08e2SPeter Avalos }
133ce0e08e2SPeter Avalos 
134ce0e08e2SPeter Avalos /*
13524c80b2bSSascha Wildner  * getlock: try to acquire the lock.
136ce0e08e2SPeter Avalos  * If file is already locked and we can sleep, put the lock in the list with
137ce0e08e2SPeter Avalos  * status LKST_WAITING; it'll be processed later.
138ce0e08e2SPeter Avalos  * Otherwise try to lock. If we're allowed to block, fork a child which
139ce0e08e2SPeter Avalos  * will do the blocking lock.
140ce0e08e2SPeter Avalos  */
141ce0e08e2SPeter Avalos enum nlm_stats
getlock(nlm4_lockargs * lckarg,struct svc_req * rqstp,int flags)142ce0e08e2SPeter Avalos getlock(nlm4_lockargs *lckarg, struct svc_req *rqstp, int flags)
143ce0e08e2SPeter Avalos {
144ce0e08e2SPeter Avalos 	struct file_lock *fl, *newfl;
145ce0e08e2SPeter Avalos 	enum nlm_stats retval;
146ce0e08e2SPeter Avalos 
147ce0e08e2SPeter Avalos 	if (grace_expired == 0 && lckarg->reclaim == 0)
148ce0e08e2SPeter Avalos 		return (flags & LOCK_V4) ?
149ce0e08e2SPeter Avalos 		    nlm4_denied_grace_period : nlm_denied_grace_period;
150ce0e08e2SPeter Avalos 
151ce0e08e2SPeter Avalos 	/* allocate new file_lock for this request */
152ce0e08e2SPeter Avalos 	newfl = malloc(sizeof(struct file_lock));
153ce0e08e2SPeter Avalos 	if (newfl == NULL) {
154ce0e08e2SPeter Avalos 		syslog(LOG_NOTICE, "malloc failed: %s", strerror(errno));
155ce0e08e2SPeter Avalos 		/* failed */
156ce0e08e2SPeter Avalos 		return (flags & LOCK_V4) ?
157ce0e08e2SPeter Avalos 		    nlm4_denied_nolock : nlm_denied_nolocks;
158ce0e08e2SPeter Avalos 	}
159ce0e08e2SPeter Avalos 	if (lckarg->alock.fh.n_len != sizeof(fhandle_t)) {
1606b882c34SSascha Wildner 		syslog(LOG_DEBUG, "received fhandle size %d, local size %d",
161ce0e08e2SPeter Avalos 		    lckarg->alock.fh.n_len, (int)sizeof(fhandle_t));
162ce0e08e2SPeter Avalos 	}
163ce0e08e2SPeter Avalos 	memcpy(&newfl->filehandle, lckarg->alock.fh.n_bytes, sizeof(fhandle_t));
164ce0e08e2SPeter Avalos 	newfl->addr = (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf;
165ce0e08e2SPeter Avalos 	newfl->client.exclusive = lckarg->exclusive;
166ce0e08e2SPeter Avalos 	newfl->client.svid = lckarg->alock.svid;
167ce0e08e2SPeter Avalos 	newfl->client.oh.n_bytes = malloc(lckarg->alock.oh.n_len);
168ce0e08e2SPeter Avalos 	if (newfl->client.oh.n_bytes == NULL) {
169ce0e08e2SPeter Avalos 		syslog(LOG_NOTICE, "malloc failed: %s", strerror(errno));
170ce0e08e2SPeter Avalos 		free(newfl);
171ce0e08e2SPeter Avalos 		return (flags & LOCK_V4) ?
172ce0e08e2SPeter Avalos 		    nlm4_denied_nolock : nlm_denied_nolocks;
173ce0e08e2SPeter Avalos 	}
174ce0e08e2SPeter Avalos 	newfl->client.oh.n_len = lckarg->alock.oh.n_len;
175ce0e08e2SPeter Avalos 	memcpy(newfl->client.oh.n_bytes, lckarg->alock.oh.n_bytes,
176ce0e08e2SPeter Avalos 	    lckarg->alock.oh.n_len);
177ce0e08e2SPeter Avalos 	newfl->client.l_offset = lckarg->alock.l_offset;
178ce0e08e2SPeter Avalos 	newfl->client.l_len = lckarg->alock.l_len;
179ce0e08e2SPeter Avalos 	newfl->client_cookie.n_len = lckarg->cookie.n_len;
180ce0e08e2SPeter Avalos 	newfl->client_cookie.n_bytes = malloc(lckarg->cookie.n_len);
181ce0e08e2SPeter Avalos 	if (newfl->client_cookie.n_bytes == NULL) {
182ce0e08e2SPeter Avalos 		syslog(LOG_NOTICE, "malloc failed: %s", strerror(errno));
183ce0e08e2SPeter Avalos 		free(newfl->client.oh.n_bytes);
184ce0e08e2SPeter Avalos 		free(newfl);
185ce0e08e2SPeter Avalos 		return (flags & LOCK_V4) ?
186ce0e08e2SPeter Avalos 		    nlm4_denied_nolock : nlm_denied_nolocks;
187ce0e08e2SPeter Avalos 	}
188ce0e08e2SPeter Avalos 	memcpy(newfl->client_cookie.n_bytes, lckarg->cookie.n_bytes,
189ce0e08e2SPeter Avalos 	    lckarg->cookie.n_len);
190ce0e08e2SPeter Avalos 	strncpy(newfl->client_name, lckarg->alock.caller_name, 128);
191ce0e08e2SPeter Avalos 	newfl->nsm_status = lckarg->state;
192ce0e08e2SPeter Avalos 	newfl->status = 0;
193ce0e08e2SPeter Avalos 	newfl->flags = flags;
194ce0e08e2SPeter Avalos 	siglock();
195ce0e08e2SPeter Avalos 	/* look for a lock rq from this host for this fh */
196ce0e08e2SPeter Avalos 	for (fl = LIST_FIRST(&lcklst_head); fl != NULL;
197ce0e08e2SPeter Avalos 	    fl = LIST_NEXT(fl, lcklst)) {
198ce0e08e2SPeter Avalos 		if (memcmp(&newfl->filehandle, &fl->filehandle,
199ce0e08e2SPeter Avalos 		    sizeof(fhandle_t)) == 0) {
200ce0e08e2SPeter Avalos 			if (strcmp(newfl->client_name, fl->client_name) == 0 &&
201ce0e08e2SPeter Avalos 			    newfl->client.svid == fl->client.svid) {
202ce0e08e2SPeter Avalos 				/* already locked by this host ??? */
203ce0e08e2SPeter Avalos 				sigunlock();
204ce0e08e2SPeter Avalos 				syslog(LOG_NOTICE, "duplicate lock from %s",
205ce0e08e2SPeter Avalos 				    newfl->client_name);
206ce0e08e2SPeter Avalos 				lfree(newfl);
207ce0e08e2SPeter Avalos 				switch(fl->status) {
208ce0e08e2SPeter Avalos 				case LKST_LOCKED:
209ce0e08e2SPeter Avalos 					return (flags & LOCK_V4) ?
210ce0e08e2SPeter Avalos 					    nlm4_granted : nlm_granted;
211ce0e08e2SPeter Avalos 				case LKST_WAITING:
212ce0e08e2SPeter Avalos 				case LKST_PROCESSING:
213ce0e08e2SPeter Avalos 					return (flags & LOCK_V4) ?
214ce0e08e2SPeter Avalos 					    nlm4_blocked : nlm_blocked;
215ce0e08e2SPeter Avalos 				case LKST_DYING:
216ce0e08e2SPeter Avalos 					return (flags & LOCK_V4) ?
217ce0e08e2SPeter Avalos 					    nlm4_denied : nlm_denied;
218ce0e08e2SPeter Avalos 				default:
219ce0e08e2SPeter Avalos 					syslog(LOG_NOTICE, "bad status %d",
220ce0e08e2SPeter Avalos 					    fl->status);
221ce0e08e2SPeter Avalos 					return (flags & LOCK_V4) ?
222ce0e08e2SPeter Avalos 					    nlm4_failed : nlm_denied;
223ce0e08e2SPeter Avalos 				}
224ce0e08e2SPeter Avalos 			}
225ce0e08e2SPeter Avalos 			/*
226ce0e08e2SPeter Avalos 			 * We already have a lock for this file. Put this one
227ce0e08e2SPeter Avalos 			 * in waiting state if allowed to block
228ce0e08e2SPeter Avalos 			 */
229ce0e08e2SPeter Avalos 			if (lckarg->block) {
230ce0e08e2SPeter Avalos 				syslog(LOG_DEBUG, "lock from %s: already "
231ce0e08e2SPeter Avalos 				    "locked, waiting",
232ce0e08e2SPeter Avalos 				    lckarg->alock.caller_name);
233ce0e08e2SPeter Avalos 				newfl->status = LKST_WAITING;
234ce0e08e2SPeter Avalos 				LIST_INSERT_HEAD(&lcklst_head, newfl, lcklst);
235ce0e08e2SPeter Avalos 				do_mon(lckarg->alock.caller_name);
236ce0e08e2SPeter Avalos 				sigunlock();
237ce0e08e2SPeter Avalos 				return (flags & LOCK_V4) ?
238ce0e08e2SPeter Avalos 				    nlm4_blocked : nlm_blocked;
239ce0e08e2SPeter Avalos 			} else {
240ce0e08e2SPeter Avalos 				sigunlock();
241ce0e08e2SPeter Avalos 				syslog(LOG_DEBUG, "lock from %s: already "
242ce0e08e2SPeter Avalos 				    "locked, failed",
243ce0e08e2SPeter Avalos 				    lckarg->alock.caller_name);
244ce0e08e2SPeter Avalos 				lfree(newfl);
245ce0e08e2SPeter Avalos 				return (flags & LOCK_V4) ?
246ce0e08e2SPeter Avalos 				    nlm4_denied : nlm_denied;
247ce0e08e2SPeter Avalos 			}
248ce0e08e2SPeter Avalos 		}
249ce0e08e2SPeter Avalos 	}
250ce0e08e2SPeter Avalos 	/* no entry for this file yet; add to list */
251ce0e08e2SPeter Avalos 	LIST_INSERT_HEAD(&lcklst_head, newfl, lcklst);
252ce0e08e2SPeter Avalos 	/* do the lock */
253ce0e08e2SPeter Avalos 	retval = do_lock(newfl, lckarg->block);
254ce0e08e2SPeter Avalos 	switch (retval) {
255ce0e08e2SPeter Avalos 	case nlm4_granted:
256ce0e08e2SPeter Avalos 	/* case nlm_granted: is the same as nlm4_granted */
257ce0e08e2SPeter Avalos 	case nlm4_blocked:
258ce0e08e2SPeter Avalos 	/* case nlm_blocked: is the same as nlm4_blocked */
259ce0e08e2SPeter Avalos 		do_mon(lckarg->alock.caller_name);
260ce0e08e2SPeter Avalos 		break;
261ce0e08e2SPeter Avalos 	default:
262ce0e08e2SPeter Avalos 		lfree(newfl);
263ce0e08e2SPeter Avalos 		break;
264ce0e08e2SPeter Avalos 	}
265ce0e08e2SPeter Avalos 	sigunlock();
266ce0e08e2SPeter Avalos 	return retval;
267ce0e08e2SPeter Avalos }
268ce0e08e2SPeter Avalos 
269ce0e08e2SPeter Avalos /* unlock a filehandle */
270ce0e08e2SPeter Avalos enum nlm_stats
unlock(nlm4_lock * lck,int flags)271ce0e08e2SPeter Avalos unlock(nlm4_lock *lck, int flags)
272ce0e08e2SPeter Avalos {
273ce0e08e2SPeter Avalos 	struct file_lock *fl;
274ce0e08e2SPeter Avalos 	fhandle_t filehandle;
275ce0e08e2SPeter Avalos 	int err = (flags & LOCK_V4) ? nlm4_granted : nlm_granted;
276ce0e08e2SPeter Avalos 
277ce0e08e2SPeter Avalos 	memcpy(&filehandle, lck->fh.n_bytes, sizeof(fhandle_t));
278ce0e08e2SPeter Avalos 	siglock();
279ce0e08e2SPeter Avalos 	for (fl = LIST_FIRST(&lcklst_head); fl != NULL;
280ce0e08e2SPeter Avalos 	    fl = LIST_NEXT(fl, lcklst)) {
281ce0e08e2SPeter Avalos 		if (strcmp(fl->client_name, lck->caller_name) ||
282ce0e08e2SPeter Avalos 		    memcmp(&filehandle, &fl->filehandle, sizeof(fhandle_t)) ||
283ce0e08e2SPeter Avalos 		    fl->client.oh.n_len != lck->oh.n_len ||
284ce0e08e2SPeter Avalos 		    memcmp(fl->client.oh.n_bytes, lck->oh.n_bytes,
285ce0e08e2SPeter Avalos 			fl->client.oh.n_len) != 0 ||
286ce0e08e2SPeter Avalos 		    fl->client.svid != lck->svid)
287ce0e08e2SPeter Avalos 			continue;
288ce0e08e2SPeter Avalos 		/* Got it, unlock and remove from the queue */
289ce0e08e2SPeter Avalos 		syslog(LOG_DEBUG, "unlock from %s: found struct, status %d",
290ce0e08e2SPeter Avalos 		    lck->caller_name, fl->status);
291ce0e08e2SPeter Avalos 		switch (fl->status) {
292ce0e08e2SPeter Avalos 		case LKST_LOCKED:
293ce0e08e2SPeter Avalos 			err = do_unlock(fl);
294ce0e08e2SPeter Avalos 			break;
295ce0e08e2SPeter Avalos 		case LKST_WAITING:
296ce0e08e2SPeter Avalos 			/* remove from the list */
297ce0e08e2SPeter Avalos 			LIST_REMOVE(fl, lcklst);
298ce0e08e2SPeter Avalos 			lfree(fl);
299ce0e08e2SPeter Avalos 			break;
300ce0e08e2SPeter Avalos 		case LKST_PROCESSING:
301ce0e08e2SPeter Avalos 			/*
302ce0e08e2SPeter Avalos 			 * being handled by a child; will clean up
303ce0e08e2SPeter Avalos 			 * when the child exits
304ce0e08e2SPeter Avalos 			 */
305ce0e08e2SPeter Avalos 			fl->status = LKST_DYING;
306ce0e08e2SPeter Avalos 			break;
307ce0e08e2SPeter Avalos 		case LKST_DYING:
308ce0e08e2SPeter Avalos 			/* nothing to do */
309ce0e08e2SPeter Avalos 			break;
310ce0e08e2SPeter Avalos 		default:
31195cdd875SSascha Wildner 			syslog(LOG_NOTICE, "unknown status %d for %s",
312ce0e08e2SPeter Avalos 			    fl->status, fl->client_name);
313ce0e08e2SPeter Avalos 		}
314ce0e08e2SPeter Avalos 		sigunlock();
315ce0e08e2SPeter Avalos 		return err;
316ce0e08e2SPeter Avalos 	}
317ce0e08e2SPeter Avalos 	sigunlock();
318ce0e08e2SPeter Avalos 	/* didn't find a matching entry; log anyway */
319ce0e08e2SPeter Avalos 	syslog(LOG_NOTICE, "no matching entry for %s",
320ce0e08e2SPeter Avalos 	    lck->caller_name);
321ce0e08e2SPeter Avalos 	return (flags & LOCK_V4) ? nlm4_granted : nlm_granted;
322ce0e08e2SPeter Avalos }
323ce0e08e2SPeter Avalos 
324ce0e08e2SPeter Avalos void
lfree(struct file_lock * fl)325ce0e08e2SPeter Avalos lfree(struct file_lock *fl)
326ce0e08e2SPeter Avalos {
327ce0e08e2SPeter Avalos 	free(fl->client.oh.n_bytes);
328ce0e08e2SPeter Avalos 	free(fl->client_cookie.n_bytes);
329ce0e08e2SPeter Avalos 	free(fl);
330ce0e08e2SPeter Avalos }
331ce0e08e2SPeter Avalos 
332ce0e08e2SPeter Avalos void
sigchild_handler(int sig)333ce0e08e2SPeter Avalos sigchild_handler(int sig)
334ce0e08e2SPeter Avalos {
335ce0e08e2SPeter Avalos 	int status;
336ce0e08e2SPeter Avalos 	pid_t pid;
337ce0e08e2SPeter Avalos 	struct file_lock *fl;
338ce0e08e2SPeter Avalos 
339ce0e08e2SPeter Avalos 	while (1) {
340ce0e08e2SPeter Avalos 		pid = wait4(-1, &status, WNOHANG, NULL);
341ce0e08e2SPeter Avalos 		if (pid == -1) {
342ce0e08e2SPeter Avalos 			if (errno != ECHILD)
343ce0e08e2SPeter Avalos 				syslog(LOG_NOTICE, "wait failed: %s",
344ce0e08e2SPeter Avalos 				    strerror(errno));
345ce0e08e2SPeter Avalos 			else
346ce0e08e2SPeter Avalos 				syslog(LOG_DEBUG, "wait failed: %s",
347ce0e08e2SPeter Avalos 				    strerror(errno));
348ce0e08e2SPeter Avalos 			return;
349ce0e08e2SPeter Avalos 		}
350ce0e08e2SPeter Avalos 		if (pid == 0) {
351ce0e08e2SPeter Avalos 			/* no more child to handle yet */
352ce0e08e2SPeter Avalos 			return;
353ce0e08e2SPeter Avalos 		}
354ce0e08e2SPeter Avalos 		/*
355ce0e08e2SPeter Avalos 		 * if we're here we have a child that exited
356ce0e08e2SPeter Avalos 		 * Find the associated file_lock.
357ce0e08e2SPeter Avalos 		 */
358ce0e08e2SPeter Avalos 		for (fl = LIST_FIRST(&lcklst_head); fl != NULL;
359ce0e08e2SPeter Avalos 		    fl = LIST_NEXT(fl, lcklst)) {
360ce0e08e2SPeter Avalos 			if (pid == fl->locker)
361ce0e08e2SPeter Avalos 				break;
362ce0e08e2SPeter Avalos 		}
363ce0e08e2SPeter Avalos 		if (pid != fl->locker) {
36495cdd875SSascha Wildner 			syslog(LOG_NOTICE, "unknown child %d", pid);
365ce0e08e2SPeter Avalos 		} else {
366ce0e08e2SPeter Avalos 			if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
367ce0e08e2SPeter Avalos 				syslog(LOG_NOTICE, "child %d failed", pid);
368ce0e08e2SPeter Avalos 				/*
369ce0e08e2SPeter Avalos 				 * can't do much here; we can't reply
370ce0e08e2SPeter Avalos 				 * anything but OK for blocked locks
371ce0e08e2SPeter Avalos 				 * Eventually the client will time out
372ce0e08e2SPeter Avalos 				 * and retry.
373ce0e08e2SPeter Avalos 				 */
374ce0e08e2SPeter Avalos 				do_unlock(fl);
375ce0e08e2SPeter Avalos 				return;
376ce0e08e2SPeter Avalos 			}
377ce0e08e2SPeter Avalos 
378ce0e08e2SPeter Avalos 			/* check lock status */
379ce0e08e2SPeter Avalos 			syslog(LOG_DEBUG, "processing child %d, status %d",
380ce0e08e2SPeter Avalos 			    pid, fl->status);
381ce0e08e2SPeter Avalos 			switch(fl->status) {
382ce0e08e2SPeter Avalos 			case LKST_PROCESSING:
383ce0e08e2SPeter Avalos 				fl->status = LKST_LOCKED;
384ce0e08e2SPeter Avalos 				send_granted(fl, (fl->flags & LOCK_V4) ?
385ce0e08e2SPeter Avalos 				    nlm4_granted : nlm_granted);
386ce0e08e2SPeter Avalos 				break;
387ce0e08e2SPeter Avalos 			case LKST_DYING:
388ce0e08e2SPeter Avalos 				do_unlock(fl);
389ce0e08e2SPeter Avalos 				break;
390ce0e08e2SPeter Avalos 			default:
391ce0e08e2SPeter Avalos 				syslog(LOG_NOTICE, "bad lock status (%d) for"
392ce0e08e2SPeter Avalos 				   " child %d", fl->status, pid);
393ce0e08e2SPeter Avalos 			}
394ce0e08e2SPeter Avalos 		}
395ce0e08e2SPeter Avalos 	}
396ce0e08e2SPeter Avalos }
397ce0e08e2SPeter Avalos 
398ce0e08e2SPeter Avalos /*
399ce0e08e2SPeter Avalos  *
40024c80b2bSSascha Wildner  * try to acquire the lock described by fl. Eventually fock a child to do a
401ce0e08e2SPeter Avalos  * blocking lock if allowed and required.
402ce0e08e2SPeter Avalos  */
403ce0e08e2SPeter Avalos 
404ce0e08e2SPeter Avalos enum nlm_stats
do_lock(struct file_lock * fl,int block)405ce0e08e2SPeter Avalos do_lock(struct file_lock *fl, int block)
406ce0e08e2SPeter Avalos {
407ce0e08e2SPeter Avalos 	int lflags, error;
408ce0e08e2SPeter Avalos 	struct stat st;
409ce0e08e2SPeter Avalos 
410ce0e08e2SPeter Avalos 	fl->fd = fhopen(&fl->filehandle, O_RDWR);
411ce0e08e2SPeter Avalos 	if (fl->fd < 0) {
412ce0e08e2SPeter Avalos 		switch (errno) {
413ce0e08e2SPeter Avalos 		case ESTALE:
414ce0e08e2SPeter Avalos 			error = nlm4_stale_fh;
415ce0e08e2SPeter Avalos 			break;
416ce0e08e2SPeter Avalos 		case EROFS:
417ce0e08e2SPeter Avalos 			error = nlm4_rofs;
418ce0e08e2SPeter Avalos 			break;
419ce0e08e2SPeter Avalos 		default:
420ce0e08e2SPeter Avalos 			error = nlm4_failed;
421ce0e08e2SPeter Avalos 		}
422ce0e08e2SPeter Avalos 		if ((fl->flags & LOCK_V4) == 0)
423ce0e08e2SPeter Avalos 			error = nlm_denied;
424ce0e08e2SPeter Avalos 		syslog(LOG_NOTICE, "fhopen failed (from %s): %s",
425ce0e08e2SPeter Avalos 		    fl->client_name, strerror(errno));
426ce0e08e2SPeter Avalos 		LIST_REMOVE(fl, lcklst);
4273598cc14SSascha Wildner 		return error;
428ce0e08e2SPeter Avalos 	}
429ce0e08e2SPeter Avalos 	if (fstat(fl->fd, &st) < 0) {
430ce0e08e2SPeter Avalos 		syslog(LOG_NOTICE, "fstat failed (from %s): %s",
431ce0e08e2SPeter Avalos 		    fl->client_name, strerror(errno));
432ce0e08e2SPeter Avalos 	}
43321eb4b7eSSascha Wildner 	syslog(LOG_DEBUG, "lock from %s for file%s%s: dev %d ino %ju (uid %d), "
434ce0e08e2SPeter Avalos 	    "flags %d",
435ce0e08e2SPeter Avalos 	    fl->client_name, fl->client.exclusive ? " (exclusive)":"",
436ce0e08e2SPeter Avalos 	    block ? " (block)":"",
43721eb4b7eSSascha Wildner 	    st.st_dev, (uintmax_t)st.st_ino, st.st_uid, fl->flags);
438ce0e08e2SPeter Avalos 	lflags = LOCK_NB;
439ce0e08e2SPeter Avalos 	if (fl->client.exclusive == 0)
440ce0e08e2SPeter Avalos 		lflags |= LOCK_SH;
441ce0e08e2SPeter Avalos 	else
442ce0e08e2SPeter Avalos 		lflags |= LOCK_EX;
443ce0e08e2SPeter Avalos 	error = flock(fl->fd, lflags);
444ce0e08e2SPeter Avalos 	if (error != 0 && errno == EAGAIN && block) {
445ce0e08e2SPeter Avalos 		switch (fl->locker = fork()) {
446ce0e08e2SPeter Avalos 		case -1: /* fork failed */
447ce0e08e2SPeter Avalos 			syslog(LOG_NOTICE, "fork failed: %s", strerror(errno));
448ce0e08e2SPeter Avalos 			LIST_REMOVE(fl, lcklst);
449ce0e08e2SPeter Avalos 			close(fl->fd);
450ce0e08e2SPeter Avalos 			return (fl->flags & LOCK_V4) ?
451ce0e08e2SPeter Avalos 			    nlm4_denied_nolock : nlm_denied_nolocks;
452ce0e08e2SPeter Avalos 		case 0:
453ce0e08e2SPeter Avalos 			/*
454ce0e08e2SPeter Avalos 			 * Attempt a blocking lock. Will have to call
455ce0e08e2SPeter Avalos 			 * NLM_GRANTED later.
456ce0e08e2SPeter Avalos 			 */
457ce0e08e2SPeter Avalos 			setproctitle("%s", fl->client_name);
458ce0e08e2SPeter Avalos 			lflags &= ~LOCK_NB;
459ce0e08e2SPeter Avalos 			if(flock(fl->fd, lflags) != 0) {
460ce0e08e2SPeter Avalos 				syslog(LOG_NOTICE, "flock failed: %s",
461ce0e08e2SPeter Avalos 				    strerror(errno));
462ce0e08e2SPeter Avalos 				exit(-1);
463ce0e08e2SPeter Avalos 			}
464ce0e08e2SPeter Avalos 			/* lock granted */
465ce0e08e2SPeter Avalos 			exit(0);
466ce0e08e2SPeter Avalos 		default:
467ce0e08e2SPeter Avalos 			syslog(LOG_DEBUG, "lock request from %s: forked %d",
468ce0e08e2SPeter Avalos 			    fl->client_name, fl->locker);
469ce0e08e2SPeter Avalos 			fl->status = LKST_PROCESSING;
470ce0e08e2SPeter Avalos 			return (fl->flags & LOCK_V4) ?
471ce0e08e2SPeter Avalos 			    nlm4_blocked : nlm_blocked;
472ce0e08e2SPeter Avalos 		}
473ce0e08e2SPeter Avalos 	}
474ce0e08e2SPeter Avalos 	/* non block case */
475ce0e08e2SPeter Avalos 	if (error != 0) {
476ce0e08e2SPeter Avalos 		switch (errno) {
477ce0e08e2SPeter Avalos 		case EAGAIN:
478ce0e08e2SPeter Avalos 			error = nlm4_denied;
479ce0e08e2SPeter Avalos 			break;
480ce0e08e2SPeter Avalos 		case ESTALE:
481ce0e08e2SPeter Avalos 			error = nlm4_stale_fh;
482ce0e08e2SPeter Avalos 			break;
483ce0e08e2SPeter Avalos 		case EROFS:
484ce0e08e2SPeter Avalos 			error = nlm4_rofs;
485ce0e08e2SPeter Avalos 			break;
486ce0e08e2SPeter Avalos 		default:
487ce0e08e2SPeter Avalos 			error = nlm4_failed;
488ce0e08e2SPeter Avalos 		}
489ce0e08e2SPeter Avalos 		if ((fl->flags & LOCK_V4) == 0)
490ce0e08e2SPeter Avalos 			error = nlm_denied;
491ce0e08e2SPeter Avalos 		if (errno != EAGAIN)
492ce0e08e2SPeter Avalos 			syslog(LOG_NOTICE, "flock for %s failed: %s",
493ce0e08e2SPeter Avalos 			    fl->client_name, strerror(errno));
494ce0e08e2SPeter Avalos 		else syslog(LOG_DEBUG, "flock for %s failed: %s",
495ce0e08e2SPeter Avalos 			    fl->client_name, strerror(errno));
496ce0e08e2SPeter Avalos 		LIST_REMOVE(fl, lcklst);
497ce0e08e2SPeter Avalos 		close(fl->fd);
498ce0e08e2SPeter Avalos 		return error;
499ce0e08e2SPeter Avalos 	}
500ce0e08e2SPeter Avalos 	fl->status = LKST_LOCKED;
501ce0e08e2SPeter Avalos 	return (fl->flags & LOCK_V4) ? nlm4_granted : nlm_granted;
502ce0e08e2SPeter Avalos }
503ce0e08e2SPeter Avalos 
504ce0e08e2SPeter Avalos void
send_granted(struct file_lock * fl,int opcode)505ce0e08e2SPeter Avalos send_granted(struct file_lock *fl, int opcode)
506ce0e08e2SPeter Avalos {
507ce0e08e2SPeter Avalos 	CLIENT *cli;
508ce0e08e2SPeter Avalos 	static char dummy;
509ce0e08e2SPeter Avalos 	struct timeval timeo;
510ce0e08e2SPeter Avalos 	int success;
511ce0e08e2SPeter Avalos 	static struct nlm_res retval;
512ce0e08e2SPeter Avalos 	static struct nlm4_res retval4;
513ce0e08e2SPeter Avalos 
514ce0e08e2SPeter Avalos 	cli = get_client(fl->addr,
515ce0e08e2SPeter Avalos 	    (fl->flags & LOCK_V4) ? NLM_VERS4 : NLM_VERS);
516ce0e08e2SPeter Avalos 	if (cli == NULL) {
517ce0e08e2SPeter Avalos 		syslog(LOG_NOTICE, "failed to get CLIENT for %s",
518ce0e08e2SPeter Avalos 		    fl->client_name);
519ce0e08e2SPeter Avalos 		/*
520ce0e08e2SPeter Avalos 		 * We fail to notify remote that the lock has been granted.
521ce0e08e2SPeter Avalos 		 * The client will timeout and retry, the lock will be
522ce0e08e2SPeter Avalos 		 * granted at this time.
523ce0e08e2SPeter Avalos 		 */
524ce0e08e2SPeter Avalos 		return;
525ce0e08e2SPeter Avalos 	}
526ce0e08e2SPeter Avalos 	timeo.tv_sec = 0;
527ce0e08e2SPeter Avalos 	timeo.tv_usec = (fl->flags & LOCK_ASYNC) ? 0 : 500000; /* 0.5s */
528ce0e08e2SPeter Avalos 
529ce0e08e2SPeter Avalos 	if (fl->flags & LOCK_V4) {
530ce0e08e2SPeter Avalos 		static nlm4_testargs res;
531ce0e08e2SPeter Avalos 		res.cookie = fl->client_cookie;
532ce0e08e2SPeter Avalos 		res.exclusive = fl->client.exclusive;
533ce0e08e2SPeter Avalos 		res.alock.caller_name = fl->client_name;
534ce0e08e2SPeter Avalos 		res.alock.fh.n_len = sizeof(fhandle_t);
535ce0e08e2SPeter Avalos 		res.alock.fh.n_bytes = (char*)&fl->filehandle;
536ce0e08e2SPeter Avalos 		res.alock.oh = fl->client.oh;
537ce0e08e2SPeter Avalos 		res.alock.svid = fl->client.svid;
538ce0e08e2SPeter Avalos 		res.alock.l_offset = fl->client.l_offset;
539ce0e08e2SPeter Avalos 		res.alock.l_len = fl->client.l_len;
540ce0e08e2SPeter Avalos 		syslog(LOG_DEBUG, "sending v4 reply%s",
541ce0e08e2SPeter Avalos 		    (fl->flags & LOCK_ASYNC) ? " (async)":"");
542ce0e08e2SPeter Avalos 		if (fl->flags & LOCK_ASYNC) {
543ce0e08e2SPeter Avalos 			success = clnt_call(cli, NLM4_GRANTED_MSG,
54473c42091SSascha Wildner 			    (xdrproc_t)xdr_nlm4_testargs, &res,
54573c42091SSascha Wildner 			    (xdrproc_t)xdr_void, &dummy, timeo);
546ce0e08e2SPeter Avalos 		} else {
547ce0e08e2SPeter Avalos 			success = clnt_call(cli, NLM4_GRANTED,
54873c42091SSascha Wildner 			    (xdrproc_t)xdr_nlm4_testargs, &res,
54973c42091SSascha Wildner 			    (xdrproc_t)xdr_nlm4_res, &retval4, timeo);
550ce0e08e2SPeter Avalos 		}
551ce0e08e2SPeter Avalos 	} else {
552ce0e08e2SPeter Avalos 		static nlm_testargs res;
553ce0e08e2SPeter Avalos 
554ce0e08e2SPeter Avalos 		res.cookie = fl->client_cookie;
555ce0e08e2SPeter Avalos 		res.exclusive = fl->client.exclusive;
556ce0e08e2SPeter Avalos 		res.alock.caller_name = fl->client_name;
557ce0e08e2SPeter Avalos 		res.alock.fh.n_len = sizeof(fhandle_t);
558ce0e08e2SPeter Avalos 		res.alock.fh.n_bytes = (char*)&fl->filehandle;
559ce0e08e2SPeter Avalos 		res.alock.oh = fl->client.oh;
560ce0e08e2SPeter Avalos 		res.alock.svid = fl->client.svid;
561ce0e08e2SPeter Avalos 		res.alock.l_offset = fl->client.l_offset;
562ce0e08e2SPeter Avalos 		res.alock.l_len = fl->client.l_len;
563ce0e08e2SPeter Avalos 		syslog(LOG_DEBUG, "sending v1 reply%s",
564ce0e08e2SPeter Avalos 		    (fl->flags & LOCK_ASYNC) ? " (async)":"");
565ce0e08e2SPeter Avalos 		if (fl->flags & LOCK_ASYNC) {
566ce0e08e2SPeter Avalos 			success = clnt_call(cli, NLM_GRANTED_MSG,
56773c42091SSascha Wildner 			    (xdrproc_t)xdr_nlm_testargs, &res,
56873c42091SSascha Wildner 			    (xdrproc_t)xdr_void, &dummy, timeo);
569ce0e08e2SPeter Avalos 		} else {
570ce0e08e2SPeter Avalos 			success = clnt_call(cli, NLM_GRANTED,
57173c42091SSascha Wildner 			    (xdrproc_t)xdr_nlm_testargs, &res,
57273c42091SSascha Wildner 			    (xdrproc_t)xdr_nlm_res, &retval, timeo);
573ce0e08e2SPeter Avalos 		}
574ce0e08e2SPeter Avalos 	}
575ce0e08e2SPeter Avalos 	if (debug_level > 2)
576ce0e08e2SPeter Avalos 		syslog(LOG_DEBUG, "clnt_call returns %d(%s) for granted",
577ce0e08e2SPeter Avalos 		    success, clnt_sperrno(success));
578ce0e08e2SPeter Avalos 
579ce0e08e2SPeter Avalos }
580ce0e08e2SPeter Avalos 
581ce0e08e2SPeter Avalos enum nlm_stats
do_unlock(struct file_lock * rfl)582ce0e08e2SPeter Avalos do_unlock(struct file_lock *rfl)
583ce0e08e2SPeter Avalos {
584ce0e08e2SPeter Avalos 	struct file_lock *fl;
585ce0e08e2SPeter Avalos 	int error;
586ce0e08e2SPeter Avalos 	int lockst;
587ce0e08e2SPeter Avalos 
588*29357d57SSascha Wildner 	/* unlock the file: closing is enough! */
589ce0e08e2SPeter Avalos 	if (close(rfl->fd) < 0) {
590ce0e08e2SPeter Avalos 		if (errno == ESTALE)
591ce0e08e2SPeter Avalos 			error = nlm4_stale_fh;
592ce0e08e2SPeter Avalos 		else
593ce0e08e2SPeter Avalos 			error = nlm4_failed;
594*29357d57SSascha Wildner 		if ((rfl->flags & LOCK_V4) == 0)
595ce0e08e2SPeter Avalos 			error = nlm_denied;
596ce0e08e2SPeter Avalos 		syslog(LOG_NOTICE,
597ce0e08e2SPeter Avalos 		    "close failed (from %s): %s",
598ce0e08e2SPeter Avalos 		    rfl->client_name, strerror(errno));
599ce0e08e2SPeter Avalos 	} else {
600*29357d57SSascha Wildner 		error = (rfl->flags & LOCK_V4) ?
601ce0e08e2SPeter Avalos 		    nlm4_granted : nlm_granted;
602ce0e08e2SPeter Avalos 	}
603ce0e08e2SPeter Avalos 	LIST_REMOVE(rfl, lcklst);
604ce0e08e2SPeter Avalos 
605ce0e08e2SPeter Avalos 	/* process the next LKST_WAITING lock request for this fh */
606ce0e08e2SPeter Avalos 	for (fl = LIST_FIRST(&lcklst_head); fl != NULL;
607ce0e08e2SPeter Avalos 	     fl = LIST_NEXT(fl, lcklst)) {
608ce0e08e2SPeter Avalos 		if (fl->status != LKST_WAITING ||
609ce0e08e2SPeter Avalos 		    memcmp(&rfl->filehandle, &fl->filehandle,
610ce0e08e2SPeter Avalos 		    sizeof(fhandle_t)) != 0)
611ce0e08e2SPeter Avalos 			continue;
612ce0e08e2SPeter Avalos 
613ce0e08e2SPeter Avalos 		lockst = do_lock(fl, 1); /* If it's LKST_WAITING we can block */
614ce0e08e2SPeter Avalos 		switch (lockst) {
615ce0e08e2SPeter Avalos 		case nlm4_granted:
616ce0e08e2SPeter Avalos 		/* case nlm_granted: same as nlm4_granted */
617ce0e08e2SPeter Avalos 			send_granted(fl, (fl->flags & LOCK_V4) ?
618ce0e08e2SPeter Avalos 			    nlm4_granted : nlm_granted);
619ce0e08e2SPeter Avalos 			break;
620ce0e08e2SPeter Avalos 		case nlm4_blocked:
621ce0e08e2SPeter Avalos 		/* case nlm_blocked: same as nlm4_blocked */
622ce0e08e2SPeter Avalos 			break;
623ce0e08e2SPeter Avalos 		default:
624ce0e08e2SPeter Avalos 			lfree(fl);
625ce0e08e2SPeter Avalos 			break;
626ce0e08e2SPeter Avalos 		}
627ce0e08e2SPeter Avalos 		break;
628ce0e08e2SPeter Avalos 	}
629ce0e08e2SPeter Avalos 	return error;
630ce0e08e2SPeter Avalos }
631ce0e08e2SPeter Avalos 
632ce0e08e2SPeter Avalos void
siglock(void)633ce0e08e2SPeter Avalos siglock(void)
634ce0e08e2SPeter Avalos {
635ce0e08e2SPeter Avalos 	sigset_t block;
636ce0e08e2SPeter Avalos 
637ce0e08e2SPeter Avalos 	sigemptyset(&block);
638ce0e08e2SPeter Avalos 	sigaddset(&block, SIGCHLD);
639ce0e08e2SPeter Avalos 
640ce0e08e2SPeter Avalos 	if (sigprocmask(SIG_BLOCK, &block, NULL) < 0) {
641ce0e08e2SPeter Avalos 		syslog(LOG_WARNING, "siglock failed: %s", strerror(errno));
642ce0e08e2SPeter Avalos 	}
643ce0e08e2SPeter Avalos }
644ce0e08e2SPeter Avalos 
645ce0e08e2SPeter Avalos void
sigunlock(void)646ce0e08e2SPeter Avalos sigunlock(void)
647ce0e08e2SPeter Avalos {
648ce0e08e2SPeter Avalos 	sigset_t block;
649ce0e08e2SPeter Avalos 
650ce0e08e2SPeter Avalos 	sigemptyset(&block);
651ce0e08e2SPeter Avalos 	sigaddset(&block, SIGCHLD);
652ce0e08e2SPeter Avalos 
653ce0e08e2SPeter Avalos 	if (sigprocmask(SIG_UNBLOCK, &block, NULL) < 0) {
654ce0e08e2SPeter Avalos 		syslog(LOG_WARNING, "sigunlock failed: %s", strerror(errno));
655ce0e08e2SPeter Avalos 	}
656ce0e08e2SPeter Avalos }
657ce0e08e2SPeter Avalos 
658ce0e08e2SPeter Avalos /* monitor a host through rpc.statd, and keep a ref count */
659ce0e08e2SPeter Avalos void
do_mon(char * hostname)660ce0e08e2SPeter Avalos do_mon(char *hostname)
661ce0e08e2SPeter Avalos {
662ce0e08e2SPeter Avalos 	struct host *hp;
663ce0e08e2SPeter Avalos 	struct mon my_mon;
664ce0e08e2SPeter Avalos 	struct sm_stat_res res;
665ce0e08e2SPeter Avalos 	int retval;
666ce0e08e2SPeter Avalos 
667ce0e08e2SPeter Avalos 	for (hp = LIST_FIRST(&hostlst_head); hp != NULL;
668ce0e08e2SPeter Avalos 	    hp = LIST_NEXT(hp, hostlst)) {
669ce0e08e2SPeter Avalos 		if (strcmp(hostname, hp->name) == 0) {
670ce0e08e2SPeter Avalos 			/* already monitored, just bump refcnt */
671ce0e08e2SPeter Avalos 			hp->refcnt++;
672ce0e08e2SPeter Avalos 			return;
673ce0e08e2SPeter Avalos 		}
674ce0e08e2SPeter Avalos 	}
675ce0e08e2SPeter Avalos 	/* not found, have to create an entry for it */
676ce0e08e2SPeter Avalos 	hp = malloc(sizeof(struct host));
677ce0e08e2SPeter Avalos 	strncpy(hp->name, hostname, SM_MAXSTRLEN);
678ce0e08e2SPeter Avalos 	hp->refcnt = 1;
679ce0e08e2SPeter Avalos 	syslog(LOG_DEBUG, "monitoring host %s",
680ce0e08e2SPeter Avalos 	    hostname);
681ce0e08e2SPeter Avalos 	memset(&my_mon, 0, sizeof(my_mon));
682ce0e08e2SPeter Avalos 	my_mon.mon_id.mon_name = hp->name;
683ce0e08e2SPeter Avalos 	my_mon.mon_id.my_id.my_name = "localhost";
684ce0e08e2SPeter Avalos 	my_mon.mon_id.my_id.my_prog = NLM_PROG;
685ce0e08e2SPeter Avalos 	my_mon.mon_id.my_id.my_vers = NLM_SM;
686ce0e08e2SPeter Avalos 	my_mon.mon_id.my_id.my_proc = NLM_SM_NOTIFY;
687ce0e08e2SPeter Avalos 	if ((retval =
68873c42091SSascha Wildner 	    callrpc("localhost", SM_PROG, SM_VERS, SM_MON, (xdrproc_t)xdr_mon,
68973c42091SSascha Wildner 	    (char*)&my_mon, (xdrproc_t)xdr_sm_stat_res, (char*)&res)) != 0) {
690ce0e08e2SPeter Avalos 		syslog(LOG_WARNING, "rpc to statd failed: %s",
691ce0e08e2SPeter Avalos 		    clnt_sperrno((enum clnt_stat)retval));
692ce0e08e2SPeter Avalos 		free(hp);
693ce0e08e2SPeter Avalos 		return;
694ce0e08e2SPeter Avalos 	}
695ce0e08e2SPeter Avalos 	if (res.res_stat == stat_fail) {
696ce0e08e2SPeter Avalos 		syslog(LOG_WARNING, "statd failed");
697ce0e08e2SPeter Avalos 		free(hp);
698ce0e08e2SPeter Avalos 		return;
699ce0e08e2SPeter Avalos 	}
700ce0e08e2SPeter Avalos 	LIST_INSERT_HEAD(&hostlst_head, hp, hostlst);
701ce0e08e2SPeter Avalos }
702ce0e08e2SPeter Avalos 
703ce0e08e2SPeter Avalos void
notify(const char * hostname,int state)704ce0e08e2SPeter Avalos notify(const char *hostname, int state)
705ce0e08e2SPeter Avalos {
706ce0e08e2SPeter Avalos 	struct file_lock *fl, *next_fl;
707ce0e08e2SPeter Avalos 	int err;
708ce0e08e2SPeter Avalos 	syslog(LOG_DEBUG, "notify from %s, new state %d", hostname, state);
709ce0e08e2SPeter Avalos 	/* search all lock for this host; if status changed, release the lock */
710ce0e08e2SPeter Avalos 	siglock();
711ce0e08e2SPeter Avalos 	for (fl = LIST_FIRST(&lcklst_head); fl != NULL; fl = next_fl) {
712ce0e08e2SPeter Avalos 		next_fl = LIST_NEXT(fl, lcklst);
713ce0e08e2SPeter Avalos 		if (strcmp(hostname, fl->client_name) == 0 &&
714ce0e08e2SPeter Avalos 		    fl->nsm_status != state) {
715ce0e08e2SPeter Avalos 			syslog(LOG_DEBUG, "state %d, nsm_state %d, unlocking",
716ce0e08e2SPeter Avalos 			    fl->status, fl->nsm_status);
717ce0e08e2SPeter Avalos 			switch(fl->status) {
718ce0e08e2SPeter Avalos 			case LKST_LOCKED:
719ce0e08e2SPeter Avalos 				err = do_unlock(fl);
720ce0e08e2SPeter Avalos 				if (err != nlm_granted)
721ce0e08e2SPeter Avalos 					syslog(LOG_DEBUG,
722ce0e08e2SPeter Avalos 					    "notify: unlock failed for %s (%d)",
723ce0e08e2SPeter Avalos 					    hostname, err);
724ce0e08e2SPeter Avalos 				break;
725ce0e08e2SPeter Avalos 			case LKST_WAITING:
726ce0e08e2SPeter Avalos 				LIST_REMOVE(fl, lcklst);
727ce0e08e2SPeter Avalos 				lfree(fl);
728ce0e08e2SPeter Avalos 				break;
729ce0e08e2SPeter Avalos 			case LKST_PROCESSING:
730ce0e08e2SPeter Avalos 				fl->status = LKST_DYING;
731ce0e08e2SPeter Avalos 				break;
732ce0e08e2SPeter Avalos 			case LKST_DYING:
733ce0e08e2SPeter Avalos 				break;
734ce0e08e2SPeter Avalos 			default:
735ce0e08e2SPeter Avalos 				syslog(LOG_NOTICE, "unknown status %d for %s",
736ce0e08e2SPeter Avalos 				    fl->status, fl->client_name);
737ce0e08e2SPeter Avalos 			}
738ce0e08e2SPeter Avalos 		}
739ce0e08e2SPeter Avalos 	}
740ce0e08e2SPeter Avalos 	sigunlock();
741ce0e08e2SPeter Avalos }
742