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