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