xref: /onnv-gate/usr/src/lib/libdscfg/common/cfg_lockdmsg.c (revision 7836:4e95154b5b7a)
1*7836SJohn.Forte@Sun.COM /*
2*7836SJohn.Forte@Sun.COM  * CDDL HEADER START
3*7836SJohn.Forte@Sun.COM  *
4*7836SJohn.Forte@Sun.COM  * The contents of this file are subject to the terms of the
5*7836SJohn.Forte@Sun.COM  * Common Development and Distribution License (the "License").
6*7836SJohn.Forte@Sun.COM  * You may not use this file except in compliance with the License.
7*7836SJohn.Forte@Sun.COM  *
8*7836SJohn.Forte@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*7836SJohn.Forte@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*7836SJohn.Forte@Sun.COM  * See the License for the specific language governing permissions
11*7836SJohn.Forte@Sun.COM  * and limitations under the License.
12*7836SJohn.Forte@Sun.COM  *
13*7836SJohn.Forte@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*7836SJohn.Forte@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*7836SJohn.Forte@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*7836SJohn.Forte@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*7836SJohn.Forte@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*7836SJohn.Forte@Sun.COM  *
19*7836SJohn.Forte@Sun.COM  * CDDL HEADER END
20*7836SJohn.Forte@Sun.COM  */
21*7836SJohn.Forte@Sun.COM /*
22*7836SJohn.Forte@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*7836SJohn.Forte@Sun.COM  * Use is subject to license terms.
24*7836SJohn.Forte@Sun.COM  */
25*7836SJohn.Forte@Sun.COM 
26*7836SJohn.Forte@Sun.COM #include <signal.h>
27*7836SJohn.Forte@Sun.COM #include <sys/types.h>
28*7836SJohn.Forte@Sun.COM #include <sys/time.h>
29*7836SJohn.Forte@Sun.COM #include <sys/socket.h>
30*7836SJohn.Forte@Sun.COM #include <netinet/in.h>
31*7836SJohn.Forte@Sun.COM #include <netinet/tcp.h>
32*7836SJohn.Forte@Sun.COM #include <netdb.h>
33*7836SJohn.Forte@Sun.COM #include <stdio.h>
34*7836SJohn.Forte@Sun.COM #include <string.h>
35*7836SJohn.Forte@Sun.COM #include <unistd.h>
36*7836SJohn.Forte@Sun.COM #include <stdlib.h>
37*7836SJohn.Forte@Sun.COM #include <errno.h>
38*7836SJohn.Forte@Sun.COM 
39*7836SJohn.Forte@Sun.COM #include "cfg_lockd.h"
40*7836SJohn.Forte@Sun.COM 
41*7836SJohn.Forte@Sun.COM static daemonaddr_t	clientaddr;
42*7836SJohn.Forte@Sun.COM static daemonaddr_t	server;
43*7836SJohn.Forte@Sun.COM 
44*7836SJohn.Forte@Sun.COM static unsigned short	server_port = CFG_SERVER_PORT;
45*7836SJohn.Forte@Sun.COM static int	lock_soc = 0;
46*7836SJohn.Forte@Sun.COM static int	pf_inet = AF_INET;
47*7836SJohn.Forte@Sun.COM static int	locked;
48*7836SJohn.Forte@Sun.COM static int	initdone;
49*7836SJohn.Forte@Sun.COM static int	initresult;
50*7836SJohn.Forte@Sun.COM static pid_t	socket_pid;
51*7836SJohn.Forte@Sun.COM 
52*7836SJohn.Forte@Sun.COM static void	cfg_lockd_reinit();
53*7836SJohn.Forte@Sun.COM 
54*7836SJohn.Forte@Sun.COM static int last_cmd = -1;
55*7836SJohn.Forte@Sun.COM static uint8_t seq = 0;
56*7836SJohn.Forte@Sun.COM 
57*7836SJohn.Forte@Sun.COM static void
send_cmd(int cmd)58*7836SJohn.Forte@Sun.COM send_cmd(int cmd)
59*7836SJohn.Forte@Sun.COM {
60*7836SJohn.Forte@Sun.COM 	struct lock_msg message_buf;
61*7836SJohn.Forte@Sun.COM 	int rc;
62*7836SJohn.Forte@Sun.COM 
63*7836SJohn.Forte@Sun.COM 	if (last_cmd == cmd) {
64*7836SJohn.Forte@Sun.COM 		message_buf.seq = seq;
65*7836SJohn.Forte@Sun.COM 	} else {
66*7836SJohn.Forte@Sun.COM 		message_buf.seq = ++seq;
67*7836SJohn.Forte@Sun.COM 		last_cmd = cmd;
68*7836SJohn.Forte@Sun.COM 	}
69*7836SJohn.Forte@Sun.COM 	message_buf.message = cmd;
70*7836SJohn.Forte@Sun.COM 	if ((message_buf.pid = getpid()) != socket_pid)
71*7836SJohn.Forte@Sun.COM 		cfg_lockd_reinit();
72*7836SJohn.Forte@Sun.COM 
73*7836SJohn.Forte@Sun.COM 	do {
74*7836SJohn.Forte@Sun.COM 		rc = sendto(lock_soc, &message_buf, sizeof (message_buf), 0,
75*7836SJohn.Forte@Sun.COM 			(struct sockaddr *)&server, sizeof (server));
76*7836SJohn.Forte@Sun.COM 	} while (rc == -1 && errno == EINTR);
77*7836SJohn.Forte@Sun.COM #ifdef CFG_LOCKD_DEBUG
78*7836SJohn.Forte@Sun.COM 	if (rc < 0) {
79*7836SJohn.Forte@Sun.COM 		perror("send");
80*7836SJohn.Forte@Sun.COM 	}
81*7836SJohn.Forte@Sun.COM #endif
82*7836SJohn.Forte@Sun.COM }
83*7836SJohn.Forte@Sun.COM 
84*7836SJohn.Forte@Sun.COM static void
read_msg(struct lock_msg * mp)85*7836SJohn.Forte@Sun.COM read_msg(struct lock_msg *mp)
86*7836SJohn.Forte@Sun.COM {
87*7836SJohn.Forte@Sun.COM 	struct sockaddr from;
88*7836SJohn.Forte@Sun.COM 	int rc, len;
89*7836SJohn.Forte@Sun.COM 
90*7836SJohn.Forte@Sun.COM 	/* wait for response */
91*7836SJohn.Forte@Sun.COM 	do {
92*7836SJohn.Forte@Sun.COM 		struct pollfd fds;
93*7836SJohn.Forte@Sun.COM 
94*7836SJohn.Forte@Sun.COM 		fds.fd = lock_soc;
95*7836SJohn.Forte@Sun.COM 		fds.events = POLLIN;
96*7836SJohn.Forte@Sun.COM 		fds.revents = 0;
97*7836SJohn.Forte@Sun.COM 
98*7836SJohn.Forte@Sun.COM 		rc = poll(&fds, 1, 500);
99*7836SJohn.Forte@Sun.COM 		if (!rc) {
100*7836SJohn.Forte@Sun.COM #ifdef CFG_LOCKD_DEBUG
101*7836SJohn.Forte@Sun.COM 			fprintf(stderr, "LOCKD: resending last command (%d)\n",
102*7836SJohn.Forte@Sun.COM 			    last_cmd);
103*7836SJohn.Forte@Sun.COM #endif
104*7836SJohn.Forte@Sun.COM 			send_cmd(last_cmd);
105*7836SJohn.Forte@Sun.COM 		}
106*7836SJohn.Forte@Sun.COM 	} while (rc == 0 ||
107*7836SJohn.Forte@Sun.COM 		(rc == -1 && errno == EINTR));
108*7836SJohn.Forte@Sun.COM 
109*7836SJohn.Forte@Sun.COM 	do {
110*7836SJohn.Forte@Sun.COM 		len = sizeof (from);
111*7836SJohn.Forte@Sun.COM 		rc = recvfrom(lock_soc, mp, sizeof (*mp), 0,
112*7836SJohn.Forte@Sun.COM 			&from, &len);
113*7836SJohn.Forte@Sun.COM 	} while (rc == -1 && errno == EINTR);
114*7836SJohn.Forte@Sun.COM #ifdef CFG_LOCKD_DEBUG
115*7836SJohn.Forte@Sun.COM 	if (rc < 0) {
116*7836SJohn.Forte@Sun.COM 		perror("revcfrom");
117*7836SJohn.Forte@Sun.COM 	}
118*7836SJohn.Forte@Sun.COM #endif
119*7836SJohn.Forte@Sun.COM }
120*7836SJohn.Forte@Sun.COM 
121*7836SJohn.Forte@Sun.COM static void
read_reply()122*7836SJohn.Forte@Sun.COM read_reply()
123*7836SJohn.Forte@Sun.COM {
124*7836SJohn.Forte@Sun.COM 	struct lock_msg message_buf;
125*7836SJohn.Forte@Sun.COM 
126*7836SJohn.Forte@Sun.COM 	do {
127*7836SJohn.Forte@Sun.COM 		read_msg(&message_buf);
128*7836SJohn.Forte@Sun.COM 	} while (message_buf.seq != seq || message_buf.message != LOCK_LOCKED);
129*7836SJohn.Forte@Sun.COM }
130*7836SJohn.Forte@Sun.COM 
131*7836SJohn.Forte@Sun.COM static void
read_ack()132*7836SJohn.Forte@Sun.COM read_ack()
133*7836SJohn.Forte@Sun.COM {
134*7836SJohn.Forte@Sun.COM 	struct lock_msg message_buf;
135*7836SJohn.Forte@Sun.COM 
136*7836SJohn.Forte@Sun.COM 	do {
137*7836SJohn.Forte@Sun.COM 		read_msg(&message_buf);
138*7836SJohn.Forte@Sun.COM 	} while (message_buf.seq != seq || message_buf.message != LOCK_ACK);
139*7836SJohn.Forte@Sun.COM }
140*7836SJohn.Forte@Sun.COM 
141*7836SJohn.Forte@Sun.COM void
cfg_lockd_rdlock()142*7836SJohn.Forte@Sun.COM cfg_lockd_rdlock()
143*7836SJohn.Forte@Sun.COM {
144*7836SJohn.Forte@Sun.COM #ifdef CFG_LOCKD_DEBUG
145*7836SJohn.Forte@Sun.COM 	FILE *fp;
146*7836SJohn.Forte@Sun.COM #endif
147*7836SJohn.Forte@Sun.COM 
148*7836SJohn.Forte@Sun.COM 	send_cmd(LOCK_READ);
149*7836SJohn.Forte@Sun.COM 	locked = 1;
150*7836SJohn.Forte@Sun.COM 	read_reply();
151*7836SJohn.Forte@Sun.COM 
152*7836SJohn.Forte@Sun.COM #ifdef CFG_LOCKD_DEBUG
153*7836SJohn.Forte@Sun.COM 	fp = fopen("/tmp/locktag", "a");
154*7836SJohn.Forte@Sun.COM 	if (fp) {
155*7836SJohn.Forte@Sun.COM 		time_t t = time(0);
156*7836SJohn.Forte@Sun.COM 		fprintf(fp, "%19.19s read  lock acquired\n", ctime(&t));
157*7836SJohn.Forte@Sun.COM 		fclose(fp);
158*7836SJohn.Forte@Sun.COM 	}
159*7836SJohn.Forte@Sun.COM 	sleep(3);
160*7836SJohn.Forte@Sun.COM #endif
161*7836SJohn.Forte@Sun.COM }
162*7836SJohn.Forte@Sun.COM 
163*7836SJohn.Forte@Sun.COM void
cfg_lockd_wrlock()164*7836SJohn.Forte@Sun.COM cfg_lockd_wrlock()
165*7836SJohn.Forte@Sun.COM {
166*7836SJohn.Forte@Sun.COM #ifdef CFG_LOCKD_DEBUG
167*7836SJohn.Forte@Sun.COM 	FILE *fp;
168*7836SJohn.Forte@Sun.COM #endif
169*7836SJohn.Forte@Sun.COM 
170*7836SJohn.Forte@Sun.COM 	send_cmd(LOCK_WRITE);
171*7836SJohn.Forte@Sun.COM 	locked = 1;
172*7836SJohn.Forte@Sun.COM 	read_reply();
173*7836SJohn.Forte@Sun.COM 
174*7836SJohn.Forte@Sun.COM #ifdef CFG_LOCKD_DEBUG
175*7836SJohn.Forte@Sun.COM 	fp = fopen("/tmp/locktag", "a");
176*7836SJohn.Forte@Sun.COM 	if (fp) {
177*7836SJohn.Forte@Sun.COM 		time_t t = time(0);
178*7836SJohn.Forte@Sun.COM 		fprintf(fp, "%19.19s write lock acquired\n", ctime(&t));
179*7836SJohn.Forte@Sun.COM 		fclose(fp);
180*7836SJohn.Forte@Sun.COM 	}
181*7836SJohn.Forte@Sun.COM 	sleep(3);
182*7836SJohn.Forte@Sun.COM #endif
183*7836SJohn.Forte@Sun.COM }
184*7836SJohn.Forte@Sun.COM 
185*7836SJohn.Forte@Sun.COM void
cfg_lockd_unlock()186*7836SJohn.Forte@Sun.COM cfg_lockd_unlock()
187*7836SJohn.Forte@Sun.COM {
188*7836SJohn.Forte@Sun.COM #ifdef CFG_LOCKD_DEBUG
189*7836SJohn.Forte@Sun.COM 	FILE *fp;
190*7836SJohn.Forte@Sun.COM #endif
191*7836SJohn.Forte@Sun.COM 
192*7836SJohn.Forte@Sun.COM 	send_cmd(LOCK_NOTLOCKED);
193*7836SJohn.Forte@Sun.COM 	read_ack();
194*7836SJohn.Forte@Sun.COM 	locked = 0;
195*7836SJohn.Forte@Sun.COM 
196*7836SJohn.Forte@Sun.COM #ifdef CFG_LOCKD_DEBUG
197*7836SJohn.Forte@Sun.COM 	fp = fopen("/tmp/locktag", "a");
198*7836SJohn.Forte@Sun.COM 	if (fp) {
199*7836SJohn.Forte@Sun.COM 		time_t t = time(0);
200*7836SJohn.Forte@Sun.COM 		fprintf(fp, "%19.19s ----- lock released\n", ctime(&t));
201*7836SJohn.Forte@Sun.COM 		fclose(fp);
202*7836SJohn.Forte@Sun.COM 	}
203*7836SJohn.Forte@Sun.COM 	sleep(3);
204*7836SJohn.Forte@Sun.COM #endif
205*7836SJohn.Forte@Sun.COM }
206*7836SJohn.Forte@Sun.COM 
207*7836SJohn.Forte@Sun.COM void
cfg_lockd_stat()208*7836SJohn.Forte@Sun.COM cfg_lockd_stat()
209*7836SJohn.Forte@Sun.COM {
210*7836SJohn.Forte@Sun.COM 	send_cmd(LOCK_STAT);
211*7836SJohn.Forte@Sun.COM }
212*7836SJohn.Forte@Sun.COM 
213*7836SJohn.Forte@Sun.COM cfglockd_t
cfg_lockedby(pid_t * pidp)214*7836SJohn.Forte@Sun.COM cfg_lockedby(pid_t *pidp)
215*7836SJohn.Forte@Sun.COM {
216*7836SJohn.Forte@Sun.COM 	struct lock_msg message_buf;
217*7836SJohn.Forte@Sun.COM 	send_cmd(LOCK_LOCKEDBY);
218*7836SJohn.Forte@Sun.COM 	read_msg(&message_buf);
219*7836SJohn.Forte@Sun.COM 	*pidp = message_buf.pid;
220*7836SJohn.Forte@Sun.COM 	return ((cfglockd_t)message_buf.message);
221*7836SJohn.Forte@Sun.COM }
222*7836SJohn.Forte@Sun.COM 
223*7836SJohn.Forte@Sun.COM static void
cfg_atexit()224*7836SJohn.Forte@Sun.COM cfg_atexit()
225*7836SJohn.Forte@Sun.COM {
226*7836SJohn.Forte@Sun.COM 	if (locked)
227*7836SJohn.Forte@Sun.COM 		cfg_lockd_unlock();
228*7836SJohn.Forte@Sun.COM }
229*7836SJohn.Forte@Sun.COM 
230*7836SJohn.Forte@Sun.COM static int
cfg_lockd_socket()231*7836SJohn.Forte@Sun.COM cfg_lockd_socket()
232*7836SJohn.Forte@Sun.COM {
233*7836SJohn.Forte@Sun.COM 	if ((lock_soc = socket(pf_inet, SOCK_DGRAM, 0)) < 0) {
234*7836SJohn.Forte@Sun.COM #ifdef CFG_LOCKD_DEBUG
235*7836SJohn.Forte@Sun.COM 		fprintf(stderr, "libcfg: failed to create socket\n");
236*7836SJohn.Forte@Sun.COM 		perror("socket");
237*7836SJohn.Forte@Sun.COM #endif
238*7836SJohn.Forte@Sun.COM 		return (-1);
239*7836SJohn.Forte@Sun.COM 	}
240*7836SJohn.Forte@Sun.COM 	clientaddr.sin_family = AF_INET;
241*7836SJohn.Forte@Sun.COM 	clientaddr.sin_addr.s_addr = INADDR_ANY;
242*7836SJohn.Forte@Sun.COM 	clientaddr.sin_port = htons(0);
243*7836SJohn.Forte@Sun.COM 	if (bind(lock_soc, (struct sockaddr *)&clientaddr,
244*7836SJohn.Forte@Sun.COM 	    sizeof (clientaddr)) < 0) {
245*7836SJohn.Forte@Sun.COM #ifdef CFG_LOCKD_DEBUG
246*7836SJohn.Forte@Sun.COM 		perror("bind");
247*7836SJohn.Forte@Sun.COM #endif
248*7836SJohn.Forte@Sun.COM 		return (-1);
249*7836SJohn.Forte@Sun.COM 	}
250*7836SJohn.Forte@Sun.COM 	socket_pid = getpid();
251*7836SJohn.Forte@Sun.COM 	return (0);
252*7836SJohn.Forte@Sun.COM }
253*7836SJohn.Forte@Sun.COM 
254*7836SJohn.Forte@Sun.COM /*
255*7836SJohn.Forte@Sun.COM  * Re-initialise after a fork has been detected.
256*7836SJohn.Forte@Sun.COM  *
257*7836SJohn.Forte@Sun.COM  * Needs to create a new socket for new process to receive messages
258*7836SJohn.Forte@Sun.COM  * from the lock daemon and enter pid into lock file so that the daemon
259*7836SJohn.Forte@Sun.COM  * can detect new processes exit if it doesn't call unlock first.
260*7836SJohn.Forte@Sun.COM  */
261*7836SJohn.Forte@Sun.COM 
262*7836SJohn.Forte@Sun.COM static void
cfg_lockd_reinit()263*7836SJohn.Forte@Sun.COM cfg_lockd_reinit()
264*7836SJohn.Forte@Sun.COM {
265*7836SJohn.Forte@Sun.COM 	if (lock_soc)
266*7836SJohn.Forte@Sun.COM 		close(lock_soc);
267*7836SJohn.Forte@Sun.COM 	lock_soc = 0;
268*7836SJohn.Forte@Sun.COM 	if (cfg_lockd_socket()) {
269*7836SJohn.Forte@Sun.COM 		initresult = 0;
270*7836SJohn.Forte@Sun.COM 		return;
271*7836SJohn.Forte@Sun.COM 	}
272*7836SJohn.Forte@Sun.COM 	cfg_enterpid();
273*7836SJohn.Forte@Sun.COM 	initresult = 1;
274*7836SJohn.Forte@Sun.COM }
275*7836SJohn.Forte@Sun.COM 
276*7836SJohn.Forte@Sun.COM int
cfg_lockd_init()277*7836SJohn.Forte@Sun.COM cfg_lockd_init()
278*7836SJohn.Forte@Sun.COM {
279*7836SJohn.Forte@Sun.COM 	struct	hostent *hp;
280*7836SJohn.Forte@Sun.COM 	FILE	*fp;
281*7836SJohn.Forte@Sun.COM 	int	pid = 0x12345678;
282*7836SJohn.Forte@Sun.COM 
283*7836SJohn.Forte@Sun.COM 	if (initdone) {
284*7836SJohn.Forte@Sun.COM 		/* only perform reinit if init worked first time */
285*7836SJohn.Forte@Sun.COM 		if (getpid() != socket_pid && initresult != 0)
286*7836SJohn.Forte@Sun.COM 			cfg_lockd_reinit();
287*7836SJohn.Forte@Sun.COM 		return (initresult);
288*7836SJohn.Forte@Sun.COM 	}
289*7836SJohn.Forte@Sun.COM 
290*7836SJohn.Forte@Sun.COM 	initdone = 1;
291*7836SJohn.Forte@Sun.COM 	initresult = 0;
292*7836SJohn.Forte@Sun.COM 
293*7836SJohn.Forte@Sun.COM 	/* check if there's a lock daemon out there */
294*7836SJohn.Forte@Sun.COM 	if ((fp = fopen(CFG_PIDFILE, "r")) == NULL)
295*7836SJohn.Forte@Sun.COM 		return (0);
296*7836SJohn.Forte@Sun.COM 	if (fscanf(fp, "%d\n", &pid) != 1) {
297*7836SJohn.Forte@Sun.COM 		fclose(fp);
298*7836SJohn.Forte@Sun.COM 		return (0);
299*7836SJohn.Forte@Sun.COM 	}
300*7836SJohn.Forte@Sun.COM 	fclose(fp);
301*7836SJohn.Forte@Sun.COM 	if (kill((pid_t)pid, 0) != 0)
302*7836SJohn.Forte@Sun.COM 		return (0);
303*7836SJohn.Forte@Sun.COM 
304*7836SJohn.Forte@Sun.COM 	/* there is a lock daemon */
305*7836SJohn.Forte@Sun.COM 	cfg_lfinit();
306*7836SJohn.Forte@Sun.COM 	cfg_enterpid();
307*7836SJohn.Forte@Sun.COM 	if (cfg_lockd_socket())
308*7836SJohn.Forte@Sun.COM 		return (0);
309*7836SJohn.Forte@Sun.COM 
310*7836SJohn.Forte@Sun.COM 	if ((hp = gethostbyname("localhost")) == NULL) {
311*7836SJohn.Forte@Sun.COM #ifdef CFG_LOCKD_DEBUG
312*7836SJohn.Forte@Sun.COM 		fprintf(stderr, "Can't find hostent for %s\n", "localhost");
313*7836SJohn.Forte@Sun.COM #endif
314*7836SJohn.Forte@Sun.COM 		return (0);
315*7836SJohn.Forte@Sun.COM 	}
316*7836SJohn.Forte@Sun.COM 	(void) memcpy(&(server.sin_addr.s_addr), *(hp->h_addr_list),
317*7836SJohn.Forte@Sun.COM 				sizeof (server.sin_addr));
318*7836SJohn.Forte@Sun.COM 	server.sin_port = htons(server_port);
319*7836SJohn.Forte@Sun.COM 	server.sin_family = hp->h_addrtype;
320*7836SJohn.Forte@Sun.COM 	endhostent();
321*7836SJohn.Forte@Sun.COM 	atexit(cfg_atexit);
322*7836SJohn.Forte@Sun.COM 	initresult = 1;
323*7836SJohn.Forte@Sun.COM 	return (1);
324*7836SJohn.Forte@Sun.COM }
325