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