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