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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 #pragma ident "%Z%%M% %I% %E% SMI" 31 32 #include "uucp.h" 33 34 #include <unistd.h> 35 #include <stdlib.h> 36 /* #include <sys/types.h> */ 37 /* #include <sys/stat.h> */ 38 39 #undef _STAT 40 #undef _FSTAT 41 42 #define _STAT stat64 43 #define _FSTAT fstat64 44 45 static void stlock(); 46 static int onelock(); 47 48 /* 49 * make a lock file with given 'name' 50 * If one already exists, send a signal 0 to the process--if 51 * it fails, then unlink it and make a new one. 52 * 53 * input: 54 * name - name of the lock file to make 55 * 56 * return: 57 * 0 -> success 58 * FAIL -> failure 59 */ 60 61 static int 62 mklock(char *name) 63 { 64 static char pid[SIZEOFPID+2] = { '\0' }; /* +2 for '\n' and NULL */ 65 static char *tempfile; 66 67 if (pid[0] == '\0') { 68 tempfile = malloc(MAXNAMESIZE); 69 if (tempfile == NULL) 70 return (FAIL); 71 (void) sprintf(pid, "%*ld\n", SIZEOFPID, (long)getpid()); 72 (void) snprintf(tempfile, MAXNAMESIZE, "%s/LTMP.%ld", X_LOCKDIR, 73 (long)getpid()); 74 } 75 76 if (onelock(pid, tempfile, name) == -1) { 77 (void) unlink(tempfile); 78 if (cklock(name)) 79 return (FAIL); 80 else { 81 if (onelock(pid, tempfile, name)) { 82 (void) unlink(tempfile); 83 DEBUG(4, "ulockf failed in onelock()\n%s", ""); 84 return (FAIL); 85 } 86 } 87 } 88 stlock(name); 89 return (0); 90 } 91 92 /* 93 * check to see if the lock file exists and is still active 94 * - use kill(pid, 0) 95 * 96 * return: 97 * 0 -> success (lock file removed - no longer active 98 * FAIL -> lock file still active 99 */ 100 static int 101 cklock(char *name) 102 { 103 int ret; 104 pid_t lpid = -1; 105 char alpid[SIZEOFPID+2]; /* +2 for '\n' and NULL */ 106 int fd; 107 108 fd = open(name, O_RDONLY); 109 DEBUG(4, "ulockf name %s\n", name); 110 if (fd == -1) { 111 if (errno == ENOENT) { /* file does not exist -- OK */ 112 return (0); 113 } 114 DEBUG(4, "Lock File--can't read (errno %d) --remove it!\n", 115 errno); 116 goto unlk; 117 } 118 ret = read(fd, (char *)alpid, SIZEOFPID + 1); /* +1 for '\n' */ 119 (void) close(fd); 120 if (ret != (SIZEOFPID+1)) { 121 122 DEBUG(4, "Lock File--bad format--remove it!\n%s", ""); 123 goto unlk; 124 } 125 lpid = (pid_t)strtol(alpid, NULL, 10); 126 if ((ret = kill(lpid, 0)) == 0 || errno == EPERM) { 127 DEBUG(4, "Lock File--process still active--not removed\n%s", 128 ""); 129 return (FAIL); 130 } 131 /* process no longer active */ 132 DEBUG(4, "kill pid (%ld), ", (long)lpid); 133 DEBUG(4, "returned %d", ret); 134 DEBUG(4, "--ok to remove lock file (%s)\n", name); 135 unlk: 136 137 if (unlink(name) != 0) { 138 DEBUG(4, "ulockf failed in unlink()\n%s", ""); 139 return (FAIL); 140 } 141 return (0); 142 } 143 144 #define MAXLOCKS 10 /* maximum number of lock files */ 145 static char *Lockfile[MAXLOCKS]; 146 static int Nlocks = 0; 147 148 /* 149 * put name in list of lock files 150 * return: 151 * none 152 */ 153 static void 154 stlock(char *name) 155 { 156 int i; 157 char *p; 158 159 for (i = 0; i < Nlocks; i++) { 160 if (Lockfile[i] == NULL) 161 break; 162 } 163 ASSERT(i < MAXLOCKS, "TOO MANY LOCKS", "", i); 164 if (i >= Nlocks) 165 i = Nlocks++; 166 p = calloc((unsigned)strlen(name) + 1, sizeof (char)); 167 ASSERT(p != NULL, "CAN NOT ALLOCATE FOR", name, 0); 168 (void) strcpy(p, name); 169 Lockfile[i] = p; 170 } 171 172 /* 173 * remove the named lock. If named lock is NULL, 174 * then remove all locks currently in list. 175 * return: 176 * none 177 */ 178 static void 179 rmlock(char *name) 180 { 181 int i; 182 183 for (i = 0; i < Nlocks; i++) { 184 if (Lockfile[i] == NULL) 185 continue; 186 if (name == NULL || EQUALS(name, Lockfile[i])) { 187 (void) unlink(Lockfile[i]); 188 free(Lockfile[i]); 189 Lockfile[i] = NULL; 190 } 191 } 192 } 193 194 /* 195 * makes a lock on behalf of pid. 196 * input: 197 * pid - process id 198 * tempfile - name of a temporary in the same file system 199 * name - lock file name (full path name) 200 * return: 201 * -1 - failed 202 * 0 - lock made successfully 203 */ 204 static int 205 onelock(char *pid, char *tempfile, char *name) 206 { 207 int fd; 208 char cb[100]; 209 210 fd = creat(tempfile, (mode_t)0444); 211 if (fd < 0) { 212 (void) snprintf(cb, sizeof (cb), 213 "%s %s %d", tempfile, name, errno); 214 logent("ULOCKC", cb); 215 if ((errno == EMFILE) || (errno == ENFILE)) 216 (void) unlink(tempfile); 217 return (-1); 218 } 219 /* +1 for '\n' */ 220 if (write(fd, pid, SIZEOFPID+1) != (SIZEOFPID+1)) { 221 (void) snprintf(cb, sizeof (cb), 222 "%s %s %d", tempfile, name, errno); 223 logent("ULOCKW", cb); 224 (void) unlink(tempfile); 225 return (-1); 226 } 227 (void) chmod(tempfile, (mode_t)0444); 228 (void) chown(tempfile, UUCPUID, UUCPGID); 229 (void) close(fd); 230 if (link(tempfile, name) < 0) { 231 DEBUG(4, "%s: ", strerror(errno)); 232 DEBUG(4, "link(%s, ", tempfile); 233 DEBUG(4, "%s)\n", name); 234 if (unlink(tempfile) < 0) { 235 (void) snprintf(cb, sizeof (cb), 236 "ULK err %s %d", tempfile, errno); 237 logent("ULOCKLNK", cb); 238 } 239 return (-1); 240 } 241 if (unlink(tempfile) < 0) { 242 (void) snprintf(cb, sizeof (cb), "%s %d", tempfile, errno); 243 logent("ULOCKF", cb); 244 } 245 return (0); 246 } 247 248 /* 249 * fd_mklock(fd) - lock the device indicated by fd is possible 250 * 251 * return - 252 * SUCCESS - this process now has the fd locked 253 * FAIL - this process was not able to lock the fd 254 */ 255 256 static int 257 fd_mklock(int fd) 258 { 259 int tries = 0; 260 struct stat64 _st_buf; 261 char lockname[BUFSIZ]; 262 263 if (_FSTAT(fd, &_st_buf) != 0) 264 return (FAIL); 265 266 (void) snprintf(lockname, sizeof (lockname), 267 "%s.%3.3lu.%3.3lu.%3.3lu", L_LOCK, 268 (unsigned long)major(_st_buf.st_dev), 269 (unsigned long)major(_st_buf.st_rdev), 270 (unsigned long)minor(_st_buf.st_rdev)); 271 272 if (mklock(lockname) == FAIL) 273 return (FAIL); 274 275 while (lockf(fd, F_TLOCK, 0L) != 0) { 276 DEBUG(7, "fd_mklock: lockf returns %d\n", errno); 277 if ((++tries >= MAX_LOCKTRY) || (errno != EAGAIN)) { 278 rmlock(lockname); 279 logent("fd_mklock", "lockf failed"); 280 return (FAIL); 281 } 282 (void) sleep(2); 283 } 284 DEBUG(7, "fd_mklock: ok\n%s", ""); 285 return (SUCCESS); 286 } 287 288 /* 289 * remove the locks associated with the device file descriptor 290 * 291 * return - 292 * SUCCESS - both BNU lock file and advisory locks removed 293 * FAIL - 294 */ 295 296 static void 297 fd_rmlock(int fd) 298 { 299 struct stat64 _st_buf; 300 char lockname[BUFSIZ]; 301 302 if (_FSTAT(fd, &_st_buf) == 0) { 303 (void) snprintf(lockname, sizeof (lockname), 304 "%s.%3.3lu.%3.3lu.%3.3lu", L_LOCK, 305 (unsigned long)major(_st_buf.st_dev), 306 (unsigned long)major(_st_buf.st_rdev), 307 (unsigned long)minor(_st_buf.st_rdev)); 308 rmlock(lockname); 309 } 310 (void) lockf(fd, F_ULOCK, 0L); 311 } 312