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