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