1/* lock.c 2 Lock and unlock a file name. 3 4 Copyright (C) 1991, 1992, 1993, 1995, 2002 Ian Lance Taylor 5 6 This file is part of the Taylor UUCP package. 7 8 This program is free software; you can redistribute it and/or 9 modify it under the terms of the GNU General Public License as 10 published by the Free Software Foundation; either version 2 of the 11 License, or (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, but 14 WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. 21 22 The author of the program may be contacted at ian@airs.com. 23 */ 24 25#include "uucp.h" 26 27#if USE_RCS_ID 28const char lock_rcsid[] = "$Id: lock.c,v 1.23 2002/03/05 19:10:42 ian Rel $"; 29#endif 30 31#include "uudefs.h" 32#include "sysdep.h" 33#include "system.h" 34 35#include <errno.h> 36#include <ctype.h> 37 38#if HAVE_FCNTL_H 39#include <fcntl.h> 40#else 41#if HAVE_SYS_FILE_H 42#include <sys/file.h> 43#endif 44#endif 45 46#if TM_IN_SYS_TIME 47#include <sys/time.h> 48#else 49#include <time.h> 50#endif 51 52#if HAVE_QNX_LOCKFILES 53#include <sys/kernel.h> 54#include <sys/psinfo.h> 55#include <sys/seginfo.h> 56#include <sys/vc.h> 57#endif 58 59#ifndef O_RDONLY 60#define O_RDONLY 0 61#define O_WRONLY 1 62#define O_RDWR 2 63#endif 64 65#ifndef O_NOCTTY 66#define O_NOCTTY 0 67#endif 68 69#ifndef SEEK_SET 70#define SEEK_SET 0 71#endif 72 73#ifndef localtime 74extern struct tm *localtime (); 75#endif 76 77#if HAVE_QNX_LOCKFILES 78static boolean fsqnx_stale P((unsigned long ipid, unsigned long inme, 79 unsigned long inid, boolean *pferr)); 80#endif 81 82/* Lock something. If the fspooldir argument is TRUE, the argument is 83 a file name relative to the spool directory; otherwise the argument 84 is a simple file name which should be created in the system lock 85 directory (under HDB this is /etc/locks). */ 86 87boolean 88fsdo_lock (zlock, fspooldir, pferr) 89 const char *zlock; 90 boolean fspooldir; 91 boolean *pferr; 92{ 93 char *zfree; 94 const char *zpath, *zslash; 95 size_t cslash; 96 pid_t ime; 97 char *ztempfile; 98 char abtempfile[sizeof "TMP12345678901234567890"]; 99 int o; 100#if HAVE_QNX_LOCKFILES 101 nid_t inme; 102 char ab[23]; 103 char *zend; 104#else 105#if HAVE_V2_LOCKFILES 106 int i; 107#else 108 char ab[12]; 109#endif 110#endif 111 int cwrote; 112 const char *zerr; 113 boolean fret; 114 115 if (pferr != NULL) 116 *pferr = TRUE; 117 118 if (fspooldir) 119 { 120 zfree = NULL; 121 zpath = zlock; 122 } 123 else 124 { 125 zfree = zsysdep_in_dir (zSlockdir, zlock); 126 zpath = zfree; 127 } 128 129 ime = getpid (); 130#if HAVE_QNX_LOCKFILES 131 inme = getnid (); 132#endif 133 134 /* We do the actual lock by creating a file and then linking it to 135 the final file name we want. This avoids race conditions due to 136 one process checking the file before we have finished writing it, 137 and also works even if we are somehow running as root. 138 139 First, create the file in the right directory (we must create the 140 file in the same directory since otherwise we might attempt a 141 cross-device link). */ 142 zslash = strrchr (zpath, '/'); 143 if (zslash == NULL) 144 cslash = 0; 145 else 146 cslash = zslash - zpath + 1; 147 148#if HAVE_QNX_LOCKFILES 149 sprintf (abtempfile, "TMP%010lx%010lx", (unsigned long) ime, 150 (unsigned long) inme); 151#else 152 sprintf (abtempfile, "TMP%010lx", (unsigned long) ime); 153#endif 154 ztempfile = zbufalc (cslash + sizeof abtempfile); 155 memcpy (ztempfile, zpath, cslash); 156 memcpy (ztempfile + cslash, abtempfile, sizeof abtempfile); 157 158 o = creat (ztempfile, IPUBLIC_FILE_MODE); 159 if (o < 0) 160 { 161 if (errno == ENOENT) 162 { 163 if (! fsysdep_make_dirs (ztempfile, FALSE)) 164 { 165 ubuffree (zfree); 166 ubuffree (ztempfile); 167 return FALSE; 168 } 169 o = creat (ztempfile, IPUBLIC_FILE_MODE); 170 } 171 if (o < 0) 172 { 173 ulog (LOG_ERROR, "creat during lock (%s in %s as uid %d): %s", ztempfile, getwd(NULL), getuid(), strerror (errno)); 174 ubuffree (zfree); 175 ubuffree (ztempfile); 176 return FALSE; 177 } 178 } 179 180#if HAVE_QNX_LOCKFILES 181 sprintf (ab, "%10ld %10ld\n", (long) ime, (long) inme); 182 cwrote = write (o, ab, strlen (ab)); 183#else 184#if HAVE_V2_LOCKFILES 185 i = (int) ime; 186 cwrote = write (o, &i, sizeof i); 187#else 188 sprintf (ab, "%10ld\n", (long) ime); 189 cwrote = write (o, ab, strlen (ab)); 190#endif 191#endif 192 193 zerr = NULL; 194 if (cwrote < 0) 195 zerr = "write"; 196 if (close (o) < 0) 197 zerr = "close"; 198 if (zerr != NULL) 199 { 200 ulog (LOG_ERROR, "%s (%s): %s", zerr, ztempfile, strerror (errno)); 201 (void) remove (ztempfile); 202 ubuffree (zfree); 203 ubuffree (ztempfile); 204 return FALSE; 205 } 206 207 /* Now try to link the file we just created to the lock file that we 208 want. If it fails, try reading the existing file to make sure 209 the process that created it still exists. We do this in a loop 210 to make it easy to retry if the old locking process no longer 211 exists. */ 212 fret = TRUE; 213 if (pferr != NULL) 214 *pferr = FALSE; 215 o = -1; 216 zerr = NULL; 217 218 while (link (ztempfile, zpath) != 0) 219 { 220 int cgot; 221 pid_t ipid; 222 boolean freadonly; 223 struct stat st; 224 char abtime[sizeof "1991-12-31 12:00:00"]; 225#if HAVE_QNX_LOCKFILES 226 nid_t inid; 227#endif 228 229 fret = FALSE; 230 231 if (errno != EEXIST) 232 { 233 ulog (LOG_ERROR, "link (%s, %s): %s", ztempfile, zpath, 234 strerror (errno)); 235 if (pferr != NULL) 236 *pferr = TRUE; 237 break; 238 } 239 240 freadonly = FALSE; 241 o = open ((char *) zpath, O_RDWR | O_NOCTTY, 0); 242 if (o < 0) 243 { 244 if (errno == EACCES) 245 { 246 freadonly = TRUE; 247 o = open ((char *) zpath, O_RDONLY, 0); 248 } 249 if (o < 0) 250 { 251 if (errno == ENOENT) 252 { 253 /* The file was presumably removed between the link 254 and the open. Try the link again. */ 255 fret = TRUE; 256 continue; 257 } 258 zerr = "open"; 259 break; 260 } 261 } 262 263 /* The race starts here. See below for a discussion. */ 264 265#if HAVE_V2_LOCKFILES 266 cgot = read (o, &i, sizeof i); 267#else 268 cgot = read (o, ab, sizeof ab - 1); 269#endif 270 271 if (cgot < 0) 272 { 273 zerr = "read"; 274 break; 275 } 276 277#if DEBUG > 0 278#if HAVE_V2_LOCKFILES 279 { 280 char ab[10]; 281 282 if (read (o, ab, sizeof ab) > 4 283 && isdigit (BUCHAR (ab[0]))) 284 ulog (LOG_ERROR, 285 "Lock file %s may be HDB format; check LOCKFILES in policy.h", 286 zpath); 287 } 288#else 289 if (cgot == 4) 290 ulog (LOG_ERROR, 291 "Lock file %s may be V2 format; check LOCKFILES in policy.h", 292 zpath); 293#endif 294#endif /* DEBUG > 0 */ 295 296#if HAVE_QNX_LOCKFILES 297 ab[cgot] = '\0'; 298 ipid = (pid_t) strtol (ab, &zend, 10); 299 inid = (nid_t) strtol (zend, (char **) NULL, 10); 300#else 301#if HAVE_V2_LOCKFILES 302 ipid = (pid_t) i; 303#else 304 ab[cgot] = '\0'; 305 ipid = (pid_t) strtol (ab, (char **) NULL, 10); 306#endif 307#endif 308 309 /* On NFS, the link might have actually succeeded even though we 310 got a failure return. This can happen if the original 311 acknowledgement was lost or delayed and the operation was 312 retried. In this case the pid will be our own. This 313 introduces a rather improbable race condition: if a stale 314 lock was left with our process ID in it, and another process 315 just did the kill, below, but has not yet changed the lock 316 file to hold its own process ID, we could start up and make 317 it all the way to here and think we have the lock. I'm not 318 going to worry about this possibility. */ 319 if (ipid == ime) 320 { 321#if HAVE_QNX_LOCKFILES 322 if (inid == inme) 323#endif 324 { 325 fret = TRUE; 326 break; 327 } 328 } 329 330 /* If the lock file is empty (cgot == 0), we assume that it is 331 stale. This can happen if the system crashed after the lock 332 file was created but before the process ID was written out. */ 333 if (cgot > 0) 334 { 335#if HAVE_QNX_LOCKFILES 336 if (! fsqnx_stale ((unsigned long) ipid, (unsigned long) inme, 337 (unsigned long) inid, pferr)) 338 break; 339#else 340 /* If the process still exists, we will get EPERM rather 341 than ESRCH. We then return FALSE to indicate that we 342 cannot make the lock. */ 343 if (kill (ipid, 0) == 0 || errno == EPERM) 344 break; 345#endif 346 } 347 348 if (fstat (o, &st) < 0) 349 strcpy (abtime, "unknown"); 350 else 351 { 352 time_t itm; 353 struct tm *q; 354 355 itm = (time_t) st.st_mtime; 356 q = localtime (&itm); 357 sprintf (abtime, "%04d-%02d-%02d %02d:%02d:%02d", 358 q->tm_year + 1900, q->tm_mon + 1, q->tm_mday, q->tm_hour, 359 q->tm_min, q->tm_sec); 360 } 361 362#if HAVE_QNX_LOCKFILES 363 ulog (LOG_ERROR, 364 "Stale lock %s held by process %ld on node %ld created %s", 365 zpath, (long) ipid, (long) inid, abtime); 366#else 367 ulog (LOG_ERROR, "Stale lock %s held by process %ld created %s", 368 zpath, (long) ipid, abtime); 369#endif 370 371 /* This is a stale lock, created by a process that no longer 372 exists. 373 374 Now we could remove the file (and, if the file mode disallows 375 writing, that's what we have to do), but we try to avoid 376 doing so since it causes a race condition. If we remove the 377 file, and are interrupted any time after we do the read until 378 we do the remove, another process could get in, open the 379 file, find that it was a stale lock, remove the file and 380 create a new one. When we regained control we would remove 381 the file the other process just created. 382 383 These files are being generated partially for the benefit of 384 cu, and it would be nice to avoid the race however cu avoids 385 it, so that the programs remain compatible. Unfortunately, 386 nobody seems to know how cu avoids the race, or even if it 387 tries to avoid it at all. 388 389 There are a few ways to avoid the race. We could use kernel 390 locking primitives, but they may not be available. We could 391 link to a special file name, but if that file were left lying 392 around then no stale lock could ever be broken (Henry Spencer 393 would think this was a good thing). 394 395 Instead I've implemented the following procedure: seek to the 396 start of the file, write our pid into it, sleep for five 397 seconds, and then make sure our pid is still there. Anybody 398 who checks the file while we're asleep will find our pid 399 there and fail the lock. The only race will come from 400 another process which has done the read by the time we do our 401 write. That process will then have five seconds to do its 402 own write. When we wake up, we'll notice that our pid is no 403 longer in the file, and retry the lock from the beginning. 404 405 This relies on the atomicity of write(2). If it possible for 406 the writes of two processes to be interleaved, the two 407 processes could livelock. POSIX unfortunately leaves this 408 case explicitly undefined; however, given that the write is 409 of less than a disk block, it's difficult to imagine an 410 interleave occurring. 411 412 Note that this is still a race. If it takes the second 413 process more than five seconds to do the kill, the lseek, and 414 the write, both processes will think they have the lock. 415 Perhaps the length of time to sleep should be configurable. 416 Even better, perhaps I should add a configuration option to 417 use a permanent lock file, which eliminates any race and 418 forces the installer to be aware of the existence of the 419 permanent lock file. 420 421 We stat the file after the sleep, to make sure some other 422 program hasn't deleted it for us. */ 423 if (freadonly) 424 { 425 (void) close (o); 426 o = -1; 427 if (remove (zpath) != 0) 428 { 429 zerr = "remove"; 430 break; 431 } 432 fret = TRUE; 433 continue; 434 } 435 436 if (lseek (o, (off_t) 0, SEEK_SET) != 0) 437 { 438 zerr = "lseek"; 439 break; 440 } 441 442#if HAVE_QNX_LOCKFILES 443 sprintf (ab, "%10ld %10ld\n", (long) ime, (long) inme); 444 cwrote = write (o, ab, strlen (ab)); 445#else 446#if HAVE_V2_LOCKFILES 447 i = (int) ime; 448 cwrote = write (o, &i, sizeof i); 449#else 450 sprintf (ab, "%10ld\n", (long) ime); 451 cwrote = write (o, ab, strlen (ab)); 452#endif 453#endif 454 455 if (cwrote < 0) 456 { 457 zerr = "write"; 458 break; 459 } 460 461 (void) sleep (5); 462 463 if (lseek (o, (off_t) 0, SEEK_SET) != 0) 464 { 465 zerr = "lseek"; 466 break; 467 } 468 469#if HAVE_V2_LOCKFILES 470 cgot = read (o, &i, sizeof i); 471#else 472 cgot = read (o, ab, sizeof ab - 1); 473#endif 474 475 if (cgot < 0) 476 { 477 zerr = "read"; 478 break; 479 } 480 481#if HAVE_QNX_LOCKFILES 482 ab[cgot] = '\0'; 483 ipid = (pid_t) strtol (ab, &zend, 10); 484 inid = (nid_t) strtol (zend, (char **) NULL, 10); 485#else 486#if HAVE_V2_LOCKFILES 487 ipid = (pid_t) i; 488#else 489 ab[cgot] = '\0'; 490 ipid = (pid_t) strtol (ab, (char **) NULL, 10); 491#endif 492#endif 493 494 if (ipid == ime) 495 { 496#if HAVE_QNX_LOCKFILES 497 if (inid == inme) 498#endif 499 { 500 struct stat sfile, sdescriptor; 501 502 /* It looks like we have the lock. Do the final stat 503 check. */ 504 if (stat ((char *) zpath, &sfile) < 0) 505 { 506 if (errno != ENOENT) 507 { 508 zerr = "stat"; 509 break; 510 } 511 /* Loop around and try again. */ 512 } 513 else 514 { 515 if (fstat (o, &sdescriptor) < 0) 516 { 517 zerr = "fstat"; 518 break; 519 } 520 521 if (sfile.st_ino == sdescriptor.st_ino 522 && sfile.st_dev == sdescriptor.st_dev) 523 { 524 /* Close the file before assuming we've 525 succeeded to pick up any trailing errors. */ 526 if (close (o) < 0) 527 { 528 zerr = "close"; 529 break; 530 } 531 532 o = -1; 533 534 /* We have the lock. */ 535 fret = TRUE; 536 break; 537 } 538 } 539 } 540 } 541 542 /* Loop around and try the lock again. We keep doing this until 543 the lock file holds a pid that exists. */ 544 (void) close (o); 545 o = -1; 546 fret = TRUE; 547 } 548 549 if (zerr != NULL) 550 { 551 ulog (LOG_ERROR, "%s (%s): %s", zerr, zpath, strerror (errno)); 552 if (pferr != NULL) 553 *pferr = TRUE; 554 } 555 556 if (o >= 0) 557 (void) close (o); 558 559 ubuffree (zfree); 560 561 /* It would be nice if we could leave the temporary file around for 562 future calls, but considering that we create lock files in 563 various different directories it's probably more trouble than 564 it's worth. */ 565 if (remove (ztempfile) != 0) 566 ulog (LOG_ERROR, "remove (%s): %s", ztempfile, strerror (errno)); 567 568 ubuffree (ztempfile); 569 570 return fret; 571} 572 573/* Unlock something. The fspooldir argument is as in fsdo_lock. */ 574 575boolean 576fsdo_unlock (zlock, fspooldir) 577 const char *zlock; 578 boolean fspooldir; 579{ 580 char *zfree; 581 const char *zpath; 582 583 if (fspooldir) 584 { 585 zfree = NULL; 586 zpath = zlock; 587 } 588 else 589 { 590 zfree = zsysdep_in_dir (zSlockdir, zlock); 591 zpath = zfree; 592 } 593 594 if (remove (zpath) == 0 595 || errno == ENOENT) 596 { 597 ubuffree (zfree); 598 return TRUE; 599 } 600 else 601 { 602 ulog (LOG_ERROR, "remove (%s): %s", zpath, strerror (errno)); 603 ubuffree (zfree); 604 return FALSE; 605 } 606} 607 608#if HAVE_QNX_LOCKFILES 609 610/* Return TRUE if the lock is stale. */ 611 612static boolean 613fsqnx_stale (ipid, inme, inid, pferr) 614 unsigned long ipid; 615 unsigned long inme; 616 unsigned long inid; 617 boolean *pferr; 618{ 619 /* A virtual process ID. This virtual process ID, which will exist 620 on the local node, will represent the process ID of the process 621 manager process (Proc) on the remote node. */ 622 pid_t ivid; 623 /* The return value of the qnx_psinfo function. This is either a 624 process ID which might or might not be the same as the process 625 being looked for, or -1 to indicate no process found. */ 626 pid_t ifound_pid; 627 /* This holds the actual result of qnx_psinfo. We will ignore 628 almost all the fields since we're just checking for existence. */ 629 struct _psinfo spsdata; 630 631 /* Establish connection with a remote process manager if necessary. */ 632 if (inid != inme) 633 { 634 ivid = qnx_vc_attach (inid /* remote node ID */, 635 PROC_PID /* pid of process manager */, 636 1000 /* initial buffer size */, 637 0 /* flags */); 638 if (ivid < 0) 639 { 640 ulog (LOG_ERROR, "qnx_vc_attach (%lu, PROC_PID): %s", 641 inid, strerror (errno)); 642 if (pferr != NULL) 643 *pferr = TRUE; 644 return FALSE; 645 } 646 } 647 else 648 { 649 /* Use the local pid of the local process manager. */ 650 ivid = PROC_PID; 651 } 652 653 /* Request the process information. */ 654 ifound_pid = qnx_psinfo (ivid /* process manager handling request */, 655 ipid /* get info on this process */, 656 &spsdata /* put info in this struct */, 657 0 /* unused */, 658 (struct _seginfo *) NULL /* unused */); 659 660 /* Deallocate the virtual connection before continuing. */ 661 { 662 int isaved_errno = errno; 663 if (qnx_vc_detach (ivid) < 0) 664 ulog (LOG_ERROR, "qnx_vd_detach (%ld): %s", (long) ivid, 665 strerror (errno)); 666 errno = isaved_errno; 667 } 668 669 /* If the returned pid matches then the process still holds the lock. */ 670 if ((ifound_pid == ipid) && (spsdata.pid == ipid)) 671 return FALSE; 672 673 /* If the returned pid is positive and doesn't match, then the 674 process doesn't exist and the lock is stale. Continue. */ 675 676 /* If the returned pid is negative (-1) and errno is EINVAL (or ESRCH 677 in older versions of QNX), then the process doesn't exist and the 678 lock is stale. Continue. */ 679 680 /* Check for impossible errors. */ 681 if ((ifound_pid < 0) && (errno != ESRCH) && (errno != EINVAL)) 682 { 683 ulog (LOG_ERROR, "qnx_psinfo (%ld, %ld): %s", (long) ivid, 684 (long) ipid, strerror (errno)); 685 /* Since we don't know what the hell this means, and we don't 686 want our system to freeze, we treat this case as a stale 687 lock. Continue on. */ 688 } 689 690 return TRUE; 691} 692 693#endif /* HAVE_QNX_LOCKFILES */ 694