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