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