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