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 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23 /* All Rights Reserved */ 24 /* 25 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 26 * Use is subject to license terms. 27 */ 28 29 #include "uucp.h" 30 31 #include <unistd.h> 32 /* #include <sys/types.h> */ 33 /* #include <sys/stat.h> */ 34 35 static struct stat _st_buf; 36 static char lockname[BUFSIZ]; 37 38 static void stlock(char *); 39 static int onelock(char *, char *, char *); 40 41 /* 42 * make a lock file with given 'name' 43 * If one already exists, send a signal 0 to the process--if 44 * it fails, then unlink it and make a new one. 45 * 46 * input: 47 * name - name of the lock file to make 48 * 49 * return: 50 * 0 -> success 51 * FAIL -> failure 52 */ 53 54 GLOBAL int 55 mklock(char *name) 56 { 57 static char pid[SIZEOFPID+2] = { '\0' }; /* +2 for '\n' and NULL */ 58 static char tempfile[MAXNAMESIZE]; 59 60 #ifdef V8 61 char *cp; 62 #endif 63 64 if (pid[0] == '\0') { 65 (void) sprintf(pid, "%*ld\n", SIZEOFPID, (long)getpid()); 66 (void) sprintf(tempfile, "%s/LTMP.%ld", X_LOCKDIR, 67 (long)getpid()); 68 } 69 70 #ifdef V8 /* this wouldn't be a problem if we used lock directories */ 71 /* some day the truncation of system names will bite us */ 72 cp = rindex(name, '/'); 73 if (cp++ != CNULL) 74 if (strlen(cp) > MAXBASENAME) 75 *(cp+MAXBASENAME) = NULLCHAR; 76 #endif /* V8 */ 77 if (onelock(pid, tempfile, name) == -1) { 78 (void) unlink(tempfile); 79 if (cklock(name)) { 80 return (FAIL); 81 } else { 82 if (onelock(pid, tempfile, name)) { 83 (void) unlink(tempfile); 84 DEBUG(4, "ulockf failed in onelock()\n%s", ""); 85 return (FAIL); 86 } 87 } 88 } 89 90 stlock(name); 91 return (0); 92 } 93 94 /* 95 * check to see if the lock file exists and is still active 96 * - use kill(pid,0) 97 * 98 * return: 99 * 0 -> success (lock file removed - no longer active 100 * FAIL -> lock file still active 101 */ 102 GLOBAL int 103 cklock(char *name) 104 { 105 int ret; 106 pid_t lpid = -1; 107 char alpid[SIZEOFPID+2]; /* +2 for '\n' and NULL */ 108 int fd; 109 110 fd = open(name, O_RDONLY); 111 DEBUG(4, "ulockf name %s\n", name); 112 if (fd == -1) { 113 if (errno == ENOENT) /* file does not exist -- OK */ 114 return (0); 115 DEBUG(4, "Lock File--can't read (errno %d) --remove it!\n", 116 errno); 117 goto unlk; 118 } 119 ret = read(fd, (char *)alpid, SIZEOFPID + 1); /* +1 for '\n' */ 120 (void) close(fd); 121 if (ret != (SIZEOFPID+1)) { 122 123 DEBUG(4, "Lock File--bad format--remove it!\n%s", ""); 124 goto unlk; 125 } 126 lpid = (pid_t)strtol(alpid, NULL, 10); 127 if ((ret = kill(lpid, 0)) == 0 || errno == EPERM) { 128 DEBUG(4, "Lock File--process still active--not removed\n%s", 129 ""); 130 return (FAIL); 131 } else { /* 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 } 136 unlk: 137 138 if (unlink(name) != 0) { 139 DEBUG(4, "ulockf failed in unlink()\n%s", ""); 140 return (FAIL); 141 } 142 return (0); 143 } 144 145 #define MAXLOCKS 10 /* maximum number of lock files */ 146 static char *Lockfile[MAXLOCKS]; 147 GLOBAL int Nlocks = 0; 148 149 /* 150 * put name in list of lock files 151 * return: 152 * none 153 */ 154 static void 155 stlock(char *name) 156 { 157 int i; 158 char *p; 159 160 for (i = 0; i < Nlocks; i++) { 161 if (Lockfile[i] == NULL) 162 break; 163 } 164 ASSERT(i < MAXLOCKS, "TOO MANY LOCKS", "", i); 165 if (i >= Nlocks) 166 i = Nlocks++; 167 p = calloc((unsigned)strlen(name) + 1, sizeof (char)); 168 ASSERT(p != NULL, "CAN NOT ALLOCATE FOR", name, 0); 169 (void) strcpy(p, name); 170 Lockfile[i] = p; 171 } 172 173 /* 174 * remove the named lock. If named lock is NULL, 175 * then remove all locks currently in list. 176 * return: 177 * none 178 */ 179 GLOBAL void 180 rmlock(char *name) 181 { 182 int i; 183 #ifdef V8 184 char *cp; 185 186 cp = rindex(name, '/'); 187 if (cp++ != CNULL) 188 if (strlen(cp) > MAXBASENAME) 189 *(cp+MAXBASENAME) = NULLCHAR; 190 #endif /* V8 */ 191 192 193 for (i = 0; i < Nlocks; i++) { 194 if (Lockfile[i] == NULL) 195 continue; 196 if (name == NULL || EQUALS(name, Lockfile[i])) { 197 (void) unlink(Lockfile[i]); 198 free(Lockfile[i]); 199 Lockfile[i] = NULL; 200 } 201 } 202 } 203 204 205 206 /* 207 * remove a lock file 208 * 209 * Parameters: 210 * pre - Path and first part of file name of the lock file to be 211 * removed. 212 * s - The suffix part of the lock file. The name of the lock file 213 * will be derrived by concatenating pre, a period, and s. 214 * 215 * return: 216 * none 217 */ 218 GLOBAL void 219 delock(char *pre, char *s) 220 { 221 char ln[MAXNAMESIZE]; 222 223 (void) sprintf(ln, "%s.%s", pre, s); 224 BASENAME(ln, '/')[MAXBASENAME] = '\0'; 225 rmlock(ln); 226 } 227 228 229 /* 230 * create lock file 231 * 232 * Parameters: 233 * pre - Path and first part of file name of the lock file to be 234 * created. 235 * name - The suffix part of the lock file. The name of the lock file 236 * will be derrived by concatenating pre, a period, and name. 237 * 238 * return: 239 * 0 -> success 240 * FAIL -> failure 241 */ 242 GLOBAL int 243 mlock(char *pre, char *name) 244 { 245 char lname[MAXNAMESIZE]; 246 247 /* 248 * if name has a '/' in it, then it's a device name and it's 249 * not in /dev (i.e., it's a remotely-mounted device or it's 250 * in a subdirectory of /dev). in either case, creating our normal 251 * lockfile (/var/spool/locks/LCK..<dev>) is going to bomb if 252 * <dev> is "/remote/dev/term/14" or "/dev/net/foo/clone", so never 253 * mind. since we're using advisory filelocks on the devices 254 * themselves, it'll be safe. 255 * 256 * of course, programs and people who are used to looking at the 257 * lockfiles to find out what's going on are going to be a trifle 258 * misled. we really need to re-consider the lockfile naming structure 259 * to accomodate devices in directories other than /dev ... maybe in 260 * the next release. 261 */ 262 if (strchr(name, '/') != NULL) 263 return (0); 264 (void) sprintf(lname, "%s.%s", pre, BASENAME(name, '/')); 265 BASENAME(lname, '/')[MAXBASENAME] = '\0'; 266 return (mklock(lname)); 267 } 268 269 /* 270 * makes a lock on behalf of pid. 271 * input: 272 * pid - process id 273 * tempfile - name of a temporary in the same file system 274 * name - lock file name (full path name) 275 * return: 276 * -1 - failed 277 * 0 - lock made successfully 278 */ 279 static int 280 onelock(char *pid, char *tempfile, char *name) 281 { 282 int fd; 283 char cb[100]; 284 285 fd = creat(tempfile, (mode_t)0444); 286 if (fd < 0) { 287 (void) sprintf(cb, "%s %s %d", tempfile, name, errno); 288 logent("ULOCKC", cb); 289 if ((errno == EMFILE) || (errno == ENFILE)) 290 (void) unlink(tempfile); 291 return (-1); 292 } 293 /* +1 for '\n' */ 294 if (write(fd, pid, SIZEOFPID + 1) != (SIZEOFPID + 1)) { 295 (void) sprintf(cb, "%s %s %d", tempfile, name, errno); 296 logent("ULOCKW", cb); 297 (void) unlink(tempfile); 298 return (-1); 299 } 300 (void) chmod(tempfile, (mode_t)0444); 301 (void) chown(tempfile, UUCPUID, UUCPGID); 302 (void) close(fd); 303 if (link(tempfile, name) < 0) { 304 DEBUG(4, "%s: ", strerror(errno)); 305 DEBUG(4, "link(%s, ", tempfile); 306 DEBUG(4, "%s)\n", name); 307 if (unlink(tempfile) < 0) { 308 (void) sprintf(cb, "ULK err %s %d", tempfile, errno); 309 logent("ULOCKLNK", cb); 310 } 311 return (-1); 312 } 313 if (unlink(tempfile) < 0) { 314 (void) sprintf(cb, "%s %d", tempfile, errno); 315 logent("ULOCKF", cb); 316 } 317 return (0); 318 } 319 320 /* 321 * fd_mklock(fd) - lock the device indicated by fd is possible 322 * 323 * return - 324 * SUCCESS - this process now has the fd locked 325 * FAIL - this process was not able to lock the fd 326 */ 327 328 GLOBAL int 329 fd_mklock(int fd) 330 { 331 int tries = 0; 332 333 if (fstat(fd, &_st_buf) != 0) 334 return (FAIL); 335 336 (void) sprintf(lockname, "%s.%3.3lu.%3.3lu.%3.3lu", L_LOCK, 337 (unsigned long) major(_st_buf.st_dev), 338 (unsigned long) major(_st_buf.st_rdev), 339 (unsigned long) minor(_st_buf.st_rdev)); 340 341 if (mklock(lockname) == FAIL) 342 return (FAIL); 343 344 while (lockf(fd, F_TLOCK, 0L) != 0) { 345 DEBUG(7, "fd_mklock: lockf returns %d\n", errno); 346 if ((++tries >= MAX_LOCKTRY) || (errno != EAGAIN)) { 347 rmlock(lockname); 348 logent("fd_mklock", "lockf failed"); 349 return (FAIL); 350 } 351 (void) sleep(2); 352 } 353 DEBUG(7, "fd_mklock: ok\n%s", ""); 354 return (SUCCESS); 355 } 356 357 /* 358 * fn_cklock(name) - determine if the device indicated by name is locked 359 * 360 * return - 361 * SUCCESS - the name is not locked 362 * FAIL - the name is locked by another process 363 */ 364 365 GLOBAL int 366 fn_cklock(char *name) 367 { 368 /* we temporarily use lockname to hold full path name */ 369 (void) sprintf(lockname, "%s%s", (*name == '/' ? "" : "/dev/"), name); 370 371 if (stat(lockname, &_st_buf) != 0) 372 return (FAIL); 373 374 (void) sprintf(lockname, "%s.%3.3lu.%3.3lu.%3.3lu", L_LOCK, 375 (unsigned long) major(_st_buf.st_dev), 376 (unsigned long) major(_st_buf.st_rdev), 377 (unsigned long) minor(_st_buf.st_rdev)); 378 379 return (cklock(lockname)); 380 } 381 382 /* 383 * fd_cklock(fd) - determine if the device indicated by fd is locked 384 * 385 * return - 386 * SUCCESS - the fd is not locked 387 * FAIL - the fd is locked by another process 388 */ 389 390 GLOBAL int 391 fd_cklock(int fd) 392 { 393 if (fstat(fd, &_st_buf) != 0) 394 return (FAIL); 395 396 (void) sprintf(lockname, "%s.%3.3lu.%3.3lu.%3.3lu", L_LOCK, 397 (unsigned long) major(_st_buf.st_dev), 398 (unsigned long) major(_st_buf.st_rdev), 399 (unsigned long) minor(_st_buf.st_rdev)); 400 401 if (cklock(lockname) == FAIL) 402 return (FAIL); 403 else 404 return (lockf(fd, F_TEST, 0L)); 405 } 406 407 /* 408 * remove the locks associated with the device file descriptor 409 * 410 * return - 411 * SUCCESS - both BNU lock file and advisory locks removed 412 * FAIL - 413 */ 414 415 GLOBAL void 416 fd_rmlock(int fd) 417 { 418 if (fstat(fd, &_st_buf) == 0) { 419 (void) sprintf(lockname, "%s.%3.3lu.%3.3lu.%3.3lu", L_LOCK, 420 (unsigned long) major(_st_buf.st_dev), 421 (unsigned long) major(_st_buf.st_rdev), 422 (unsigned long) minor(_st_buf.st_rdev)); 423 rmlock(lockname); 424 } 425 (void) lockf(fd, F_ULOCK, 0L); 426 } 427