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