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