diff options
Diffstat (limited to 'src/filelock.c')
| -rw-r--r-- | src/filelock.c | 439 |
1 files changed, 252 insertions, 187 deletions
diff --git a/src/filelock.c b/src/filelock.c index 14b9d4aaca5..32992896c2b 100644 --- a/src/filelock.c +++ b/src/filelock.c | |||
| @@ -38,6 +38,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 38 | 38 | ||
| 39 | #include <errno.h> | 39 | #include <errno.h> |
| 40 | 40 | ||
| 41 | #include <c-ctype.h> | ||
| 42 | |||
| 41 | #include "lisp.h" | 43 | #include "lisp.h" |
| 42 | #include "character.h" | 44 | #include "character.h" |
| 43 | #include "buffer.h" | 45 | #include "buffer.h" |
| @@ -64,7 +66,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 64 | #define WTMP_FILE "/var/log/wtmp" | 66 | #define WTMP_FILE "/var/log/wtmp" |
| 65 | #endif | 67 | #endif |
| 66 | 68 | ||
| 67 | /* On non-MS-Windows systems, use a symbolic link to represent a lock. | 69 | /* Normally use a symbolic link to represent a lock. |
| 68 | The strategy: to lock a file FN, create a symlink .#FN in FN's | 70 | The strategy: to lock a file FN, create a symlink .#FN in FN's |
| 69 | directory, with link data `user@host.pid'. This avoids a single | 71 | directory, with link data `user@host.pid'. This avoids a single |
| 70 | mount (== failure) point for lock files. | 72 | mount (== failure) point for lock files. |
| @@ -100,10 +102,21 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 100 | 102 | ||
| 101 | --karl@cs.umb.edu/karl@hq.ileaf.com. | 103 | --karl@cs.umb.edu/karl@hq.ileaf.com. |
| 102 | 104 | ||
| 103 | On MS-Windows, symbolic links do not work well, so instead of a | 105 | On some file systems, notably those of MS-Windows, symbolic links |
| 104 | symlink .#FN -> 'user@host.pid', the lock is a regular file .#-FN | 106 | do not work well, so instead of a symlink .#FN -> 'user@host.pid', |
| 105 | with contents 'user@host.pid'. MS-Windows and non-MS-Windows | 107 | the lock is a regular file .#FN with contents 'user@host.pid'. To |
| 106 | versions of Emacs ignore each other's locks. */ | 108 | establish a lock, a nonce file is created and then renamed to .#FN. |
| 109 | On MS-Windows this renaming is atomic unless the lock is forcibly | ||
| 110 | acquired. On other systems the renaming is atomic if the lock is | ||
| 111 | forcibly acquired; if not, the renaming is done via hard links, | ||
| 112 | which is good enough for lock-file purposes. | ||
| 113 | |||
| 114 | To summarize, race conditions can occur with either: | ||
| 115 | |||
| 116 | * Forced locks on MS-Windows systems. | ||
| 117 | |||
| 118 | * Non-forced locks on non-MS-Windows systems that support neither | ||
| 119 | hard nor symbolic links. */ | ||
| 107 | 120 | ||
| 108 | 121 | ||
| 109 | /* Return the time of the last system boot. */ | 122 | /* Return the time of the last system boot. */ |
| @@ -284,30 +297,31 @@ get_boot_time_1 (const char *filename, bool newest) | |||
| 284 | } | 297 | } |
| 285 | #endif /* BOOT_TIME */ | 298 | #endif /* BOOT_TIME */ |
| 286 | 299 | ||
| 300 | /* An arbitrary limit on lock contents length. 8 K should be plenty | ||
| 301 | big enough in practice. */ | ||
| 302 | enum { MAX_LFINFO = 8 * 1024 }; | ||
| 303 | |||
| 287 | /* Here is the structure that stores information about a lock. */ | 304 | /* Here is the structure that stores information about a lock. */ |
| 288 | 305 | ||
| 289 | typedef struct | 306 | typedef struct |
| 290 | { | 307 | { |
| 291 | char *user; | 308 | /* Location of '@', '.', ':' in USER. If there's no colon, COLON |
| 292 | char *host; | 309 | points to the end of USER. */ |
| 293 | pid_t pid; | 310 | char *at, *dot, *colon; |
| 294 | time_t boot_time; | ||
| 295 | } lock_info_type; | ||
| 296 | |||
| 297 | /* Free the two dynamically-allocated pieces in PTR. */ | ||
| 298 | #define FREE_LOCK_INFO(i) do { xfree ((i).user); xfree ((i).host); } while (0) | ||
| 299 | 311 | ||
| 300 | #ifdef WINDOWSNT | 312 | /* Lock file contents USER@HOST.PID with an optional :BOOT_TIME |
| 301 | enum { defined_WINDOWSNT = 1 }; | 313 | appended. This memory is used as a lock file contents buffer, so |
| 302 | #else | 314 | it needs room for MAX_LFINFO + 1 bytes. A string " (pid NNNN)" |
| 303 | enum { defined_WINDOWSNT = 0 }; | 315 | may be appended to the USER@HOST while generating a diagnostic, |
| 304 | #endif | 316 | so make room for its extra bytes (as opposed to ".NNNN") too. */ |
| 317 | char user[MAX_LFINFO + 1 + sizeof " (pid )" - sizeof "."]; | ||
| 318 | } lock_info_type; | ||
| 305 | 319 | ||
| 306 | /* Write the name of the lock file for FNAME into LOCKNAME. Length | 320 | /* Write the name of the lock file for FNAME into LOCKNAME. Length |
| 307 | will be that of FNAME plus two more for the leading ".#", | 321 | will be that of FNAME plus two more for the leading ".#", plus one |
| 308 | plus one for "-" if MS-Windows, plus one for the null. */ | 322 | for the null. */ |
| 309 | #define MAKE_LOCK_NAME(lockname, fname) \ | 323 | #define MAKE_LOCK_NAME(lockname, fname) \ |
| 310 | (lockname = SAFE_ALLOCA (SBYTES (fname) + 2 + defined_WINDOWSNT + 1), \ | 324 | (lockname = SAFE_ALLOCA (SBYTES (fname) + 2 + 1), \ |
| 311 | fill_in_lock_file_name (lockname, fname)) | 325 | fill_in_lock_file_name (lockname, fname)) |
| 312 | 326 | ||
| 313 | static void | 327 | static void |
| @@ -319,70 +333,131 @@ fill_in_lock_file_name (char *lockfile, Lisp_Object fn) | |||
| 319 | memcpy (lockfile, SSDATA (fn), dirlen); | 333 | memcpy (lockfile, SSDATA (fn), dirlen); |
| 320 | lockfile[dirlen] = '.'; | 334 | lockfile[dirlen] = '.'; |
| 321 | lockfile[dirlen + 1] = '#'; | 335 | lockfile[dirlen + 1] = '#'; |
| 322 | if (defined_WINDOWSNT) | 336 | strcpy (lockfile + dirlen + 2, base); |
| 323 | lockfile[dirlen + 2] = '-'; | ||
| 324 | strcpy (lockfile + dirlen + 2 + defined_WINDOWSNT, base); | ||
| 325 | } | 337 | } |
| 326 | 338 | ||
| 339 | /* For some reason Linux kernels return EPERM on file systems that do | ||
| 340 | not support hard or symbolic links. This symbol documents the quirk. | ||
| 341 | There is no way to tell whether a symlink call fails due to | ||
| 342 | permissions issues or because links are not supported, but luckily | ||
| 343 | the lock file code should work either way. */ | ||
| 344 | enum { LINKS_MIGHT_NOT_WORK = EPERM }; | ||
| 345 | |||
| 346 | /* Rename OLD to NEW. If FORCE, replace any existing NEW. | ||
| 347 | It is OK if there are temporarily two hard links to OLD. | ||
| 348 | Return 0 if successful, -1 (setting errno) otherwise. */ | ||
| 327 | static int | 349 | static int |
| 328 | create_lock_file (char *lfname, char *lock_info_str, bool force) | 350 | rename_lock_file (char const *old, char const *new, bool force) |
| 329 | { | 351 | { |
| 330 | int err; | ||
| 331 | |||
| 332 | #ifdef WINDOWSNT | 352 | #ifdef WINDOWSNT |
| 333 | /* Symlinks are supported only by latest versions of Windows, and | 353 | return sys_rename_replace (old, new, force); |
| 334 | creating them is a privileged operation that often triggers UAC | 354 | #else |
| 335 | elevation prompts. Therefore, instead of using symlinks, we | 355 | if (! force) |
| 336 | create a regular file with the lock info written as its | 356 | { |
| 337 | contents. */ | 357 | struct stat st; |
| 338 | { | ||
| 339 | /* Deny everybody else any kind of access to the file until we are | ||
| 340 | done writing it and close the handle. This makes the entire | ||
| 341 | open/write/close operation atomic, as far as other WINDOWSNT | ||
| 342 | processes are concerned. */ | ||
| 343 | int fd = _sopen (lfname, | ||
| 344 | _O_WRONLY | _O_BINARY | _O_CREAT | _O_EXCL | _O_NOINHERIT, | ||
| 345 | _SH_DENYRW, S_IREAD | S_IWRITE); | ||
| 346 | |||
| 347 | if (fd < 0 && errno == EEXIST && force) | ||
| 348 | fd = _sopen (lfname, _O_WRONLY | _O_BINARY | _O_TRUNC |_O_NOINHERIT, | ||
| 349 | _SH_DENYRW, S_IREAD | S_IWRITE); | ||
| 350 | if (fd >= 0) | ||
| 351 | { | ||
| 352 | ssize_t lock_info_len = strlen (lock_info_str); | ||
| 353 | 358 | ||
| 354 | err = 0; | 359 | if (link (old, new) == 0) |
| 355 | if (emacs_write (fd, lock_info_str, lock_info_len) != lock_info_len) | 360 | return unlink (old) == 0 || errno == ENOENT ? 0 : -1; |
| 356 | err = -1; | 361 | if (errno != ENOSYS && errno != LINKS_MIGHT_NOT_WORK) |
| 357 | if (emacs_close (fd)) | 362 | return -1; |
| 358 | err = -1; | 363 | |
| 359 | } | 364 | /* 'link' does not work on this file system. This can occur on |
| 360 | else | 365 | a GNU/Linux host mounting a FAT32 file system. Fall back on |
| 361 | err = -1; | 366 | 'rename' after checking that NEW does not exist. There is a |
| 362 | } | 367 | potential race condition since some other process may create |
| 368 | NEW immediately after the existence check, but it's the best | ||
| 369 | we can portably do here. */ | ||
| 370 | if (lstat (new, &st) == 0 || errno == EOVERFLOW) | ||
| 371 | { | ||
| 372 | errno = EEXIST; | ||
| 373 | return -1; | ||
| 374 | } | ||
| 375 | if (errno != ENOENT) | ||
| 376 | return -1; | ||
| 377 | } | ||
| 378 | |||
| 379 | return rename (old, new); | ||
| 380 | #endif | ||
| 381 | } | ||
| 382 | |||
| 383 | /* Create the lock file FILE with contents CONTENTS. Return 0 if | ||
| 384 | successful, an errno value on failure. If FORCE, remove any | ||
| 385 | existing FILE if necessary. */ | ||
| 386 | |||
| 387 | static int | ||
| 388 | create_lock_file (char *lfname, char *lock_info_str, bool force) | ||
| 389 | { | ||
| 390 | #ifdef WINDOWSNT | ||
| 391 | /* Symlinks are supported only by later versions of Windows, and | ||
| 392 | creating them is a privileged operation that often triggers | ||
| 393 | User Account Control elevation prompts. Avoid the problem by | ||
| 394 | pretending that 'symlink' does not work. */ | ||
| 395 | int err = ENOSYS; | ||
| 363 | #else | 396 | #else |
| 364 | err = symlink (lock_info_str, lfname); | 397 | int err = symlink (lock_info_str, lfname) == 0 ? 0 : errno; |
| 365 | if (err != 0 && errno == EEXIST && force) | 398 | #endif |
| 399 | |||
| 400 | if (err == EEXIST && force) | ||
| 366 | { | 401 | { |
| 367 | unlink (lfname); | 402 | unlink (lfname); |
| 368 | err = symlink (lock_info_str, lfname); | 403 | err = symlink (lock_info_str, lfname) == 0 ? 0 : errno; |
| 369 | } | 404 | } |
| 405 | |||
| 406 | if (err == ENOSYS || err == LINKS_MIGHT_NOT_WORK || err == ENAMETOOLONG) | ||
| 407 | { | ||
| 408 | static char const nonce_base[] = ".#-emacsXXXXXX"; | ||
| 409 | char *last_slash = strrchr (lfname, '/'); | ||
| 410 | ptrdiff_t lfdirlen = last_slash + 1 - lfname; | ||
| 411 | USE_SAFE_ALLOCA; | ||
| 412 | char *nonce = SAFE_ALLOCA (lfdirlen + sizeof nonce_base); | ||
| 413 | int fd; | ||
| 414 | bool need_fchmod; | ||
| 415 | mode_t world_readable = S_IRUSR | S_IRGRP | S_IROTH; | ||
| 416 | memcpy (nonce, lfname, lfdirlen); | ||
| 417 | strcpy (nonce + lfdirlen, nonce_base); | ||
| 418 | |||
| 419 | #if HAVE_MKSTEMP | ||
| 420 | /* Prefer mkstemp if available, as it avoids a race between | ||
| 421 | mktemp and emacs_open. */ | ||
| 422 | fd = mkstemp (nonce); | ||
| 423 | need_fchmod = 1; | ||
| 424 | #else | ||
| 425 | mktemp (nonce); | ||
| 426 | fd = emacs_open (nonce, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, | ||
| 427 | world_readable); | ||
| 428 | need_fchmod = 0; | ||
| 370 | #endif | 429 | #endif |
| 371 | 430 | ||
| 431 | if (fd < 0) | ||
| 432 | err = errno; | ||
| 433 | else | ||
| 434 | { | ||
| 435 | ptrdiff_t lock_info_len = strlen (lock_info_str); | ||
| 436 | err = 0; | ||
| 437 | if (emacs_write (fd, lock_info_str, lock_info_len) != lock_info_len | ||
| 438 | || (need_fchmod && fchmod (fd, world_readable) != 0)) | ||
| 439 | err = errno; | ||
| 440 | if (emacs_close (fd) != 0) | ||
| 441 | err = errno; | ||
| 442 | if (!err && rename_lock_file (nonce, lfname, force) != 0) | ||
| 443 | err = errno; | ||
| 444 | if (err) | ||
| 445 | unlink (nonce); | ||
| 446 | } | ||
| 447 | |||
| 448 | SAFE_FREE (); | ||
| 449 | } | ||
| 450 | |||
| 372 | return err; | 451 | return err; |
| 373 | } | 452 | } |
| 374 | 453 | ||
| 375 | /* Lock the lock file named LFNAME. | 454 | /* Lock the lock file named LFNAME. |
| 376 | If FORCE, do so even if it is already locked. | 455 | If FORCE, do so even if it is already locked. |
| 377 | Return true if successful. */ | 456 | Return 0 if successful, an error number on failure. */ |
| 378 | 457 | ||
| 379 | static bool | 458 | static int |
| 380 | lock_file_1 (char *lfname, bool force) | 459 | lock_file_1 (char *lfname, bool force) |
| 381 | { | 460 | { |
| 382 | int err; | ||
| 383 | int symlink_errno; | ||
| 384 | USE_SAFE_ALLOCA; | ||
| 385 | |||
| 386 | /* Call this first because it can GC. */ | 461 | /* Call this first because it can GC. */ |
| 387 | printmax_t boot = get_boot_time (); | 462 | printmax_t boot = get_boot_time (); |
| 388 | 463 | ||
| @@ -390,20 +465,16 @@ lock_file_1 (char *lfname, bool force) | |||
| 390 | char const *user_name = STRINGP (luser_name) ? SSDATA (luser_name) : ""; | 465 | char const *user_name = STRINGP (luser_name) ? SSDATA (luser_name) : ""; |
| 391 | Lisp_Object lhost_name = Fsystem_name (); | 466 | Lisp_Object lhost_name = Fsystem_name (); |
| 392 | char const *host_name = STRINGP (lhost_name) ? SSDATA (lhost_name) : ""; | 467 | char const *host_name = STRINGP (lhost_name) ? SSDATA (lhost_name) : ""; |
| 393 | ptrdiff_t lock_info_size = (strlen (user_name) + strlen (host_name) | 468 | char lock_info_str[MAX_LFINFO + 1]; |
| 394 | + 2 * INT_STRLEN_BOUND (printmax_t) | ||
| 395 | + sizeof "@.:"); | ||
| 396 | char *lock_info_str = SAFE_ALLOCA (lock_info_size); | ||
| 397 | printmax_t pid = getpid (); | 469 | printmax_t pid = getpid (); |
| 398 | 470 | ||
| 399 | esprintf (lock_info_str, boot ? "%s@%s.%"pMd":%"pMd : "%s@%s.%"pMd, | 471 | if (sizeof lock_info_str |
| 400 | user_name, host_name, pid, boot); | 472 | <= snprintf (lock_info_str, sizeof lock_info_str, |
| 401 | err = create_lock_file (lfname, lock_info_str, force); | 473 | boot ? "%s@%s.%"pMd":%"pMd : "%s@%s.%"pMd, |
| 474 | user_name, host_name, pid, boot)) | ||
| 475 | return ENAMETOOLONG; | ||
| 402 | 476 | ||
| 403 | symlink_errno = errno; | 477 | return create_lock_file (lfname, lock_info_str, force); |
| 404 | SAFE_FREE (); | ||
| 405 | errno = symlink_errno; | ||
| 406 | return err == 0; | ||
| 407 | } | 478 | } |
| 408 | 479 | ||
| 409 | /* Return true if times A and B are no more than one second apart. */ | 480 | /* Return true if times A and B are no more than one second apart. */ |
| @@ -414,32 +485,44 @@ within_one_second (time_t a, time_t b) | |||
| 414 | return (a - b >= -1 && a - b <= 1); | 485 | return (a - b >= -1 && a - b <= 1); |
| 415 | } | 486 | } |
| 416 | 487 | ||
| 417 | static Lisp_Object | 488 | /* On systems lacking ELOOP, test for an errno value that shouldn't occur. */ |
| 418 | read_lock_data (char *lfname) | 489 | #ifndef ELOOP |
| 419 | { | 490 | # define ELOOP (-1) |
| 420 | #ifndef WINDOWSNT | 491 | #endif |
| 421 | return emacs_readlinkat (AT_FDCWD, lfname); | ||
| 422 | #else | ||
| 423 | int fd = emacs_open (lfname, O_RDONLY | O_BINARY, S_IREAD); | ||
| 424 | ssize_t nbytes; | ||
| 425 | /* 256 chars for user, 1024 chars for host, 10 digits for each of 2 int's. */ | ||
| 426 | enum { MAX_LFINFO = 256 + 1024 + 10 + 10 + 2 }; | ||
| 427 | char lfinfo[MAX_LFINFO + 1]; | ||
| 428 | 492 | ||
| 429 | if (fd < 0) | 493 | /* Read the data for the lock file LFNAME into LFINFO. Read at most |
| 430 | return Qnil; | 494 | MAX_LFINFO + 1 bytes. Return the number of bytes read, or -1 |
| 495 | (setting errno) on error. */ | ||
| 431 | 496 | ||
| 432 | nbytes = emacs_read (fd, lfinfo, MAX_LFINFO); | 497 | static ptrdiff_t |
| 433 | emacs_close (fd); | 498 | read_lock_data (char *lfname, char lfinfo[MAX_LFINFO + 1]) |
| 499 | { | ||
| 500 | ptrdiff_t nbytes; | ||
| 434 | 501 | ||
| 435 | if (nbytes > 0) | 502 | while ((nbytes = readlinkat (AT_FDCWD, lfname, lfinfo, MAX_LFINFO + 1)) < 0 |
| 503 | && errno == EINVAL) | ||
| 436 | { | 504 | { |
| 437 | lfinfo[nbytes] = '\0'; | 505 | int fd = emacs_open (lfname, O_RDONLY | O_BINARY | O_NOFOLLOW, 0); |
| 438 | return build_string (lfinfo); | 506 | if (0 <= fd) |
| 507 | { | ||
| 508 | ptrdiff_t read_bytes = emacs_read (fd, lfinfo, MAX_LFINFO + 1); | ||
| 509 | int read_errno = errno; | ||
| 510 | if (emacs_close (fd) != 0) | ||
| 511 | return -1; | ||
| 512 | errno = read_errno; | ||
| 513 | return read_bytes; | ||
| 514 | } | ||
| 515 | |||
| 516 | if (errno != ELOOP) | ||
| 517 | return -1; | ||
| 518 | |||
| 519 | /* readlinkat saw a non-symlink, but emacs_open saw a symlink. | ||
| 520 | The former must have been removed and replaced by the latter. | ||
| 521 | Try again. */ | ||
| 522 | QUIT; | ||
| 439 | } | 523 | } |
| 440 | else | 524 | |
| 441 | return Qnil; | 525 | return nbytes; |
| 442 | #endif | ||
| 443 | } | 526 | } |
| 444 | 527 | ||
| 445 | /* Return 0 if nobody owns the lock file LFNAME or the lock is obsolete, | 528 | /* Return 0 if nobody owns the lock file LFNAME or the lock is obsolete, |
| @@ -451,83 +534,78 @@ static int | |||
| 451 | current_lock_owner (lock_info_type *owner, char *lfname) | 534 | current_lock_owner (lock_info_type *owner, char *lfname) |
| 452 | { | 535 | { |
| 453 | int ret; | 536 | int ret; |
| 454 | ptrdiff_t len; | ||
| 455 | lock_info_type local_owner; | 537 | lock_info_type local_owner; |
| 456 | intmax_t n; | 538 | ptrdiff_t lfinfolen; |
| 457 | char *at, *dot, *colon; | 539 | intmax_t pid, boot_time; |
| 458 | Lisp_Object lfinfo_object = read_lock_data (lfname); | 540 | char *at, *dot, *lfinfo_end; |
| 459 | char *lfinfo; | ||
| 460 | struct gcpro gcpro1; | ||
| 461 | |||
| 462 | /* If nonexistent lock file, all is well; otherwise, got strange error. */ | ||
| 463 | if (NILP (lfinfo_object)) | ||
| 464 | return errno == ENOENT ? 0 : -1; | ||
| 465 | lfinfo = SSDATA (lfinfo_object); | ||
| 466 | 541 | ||
| 467 | /* Even if the caller doesn't want the owner info, we still have to | 542 | /* Even if the caller doesn't want the owner info, we still have to |
| 468 | read it to determine return value. */ | 543 | read it to determine return value. */ |
| 469 | if (!owner) | 544 | if (!owner) |
| 470 | owner = &local_owner; | 545 | owner = &local_owner; |
| 471 | 546 | ||
| 547 | /* If nonexistent lock file, all is well; otherwise, got strange error. */ | ||
| 548 | lfinfolen = read_lock_data (lfname, owner->user); | ||
| 549 | if (lfinfolen < 0) | ||
| 550 | return errno == ENOENT ? 0 : -1; | ||
| 551 | if (MAX_LFINFO < lfinfolen) | ||
| 552 | return -1; | ||
| 553 | owner->user[lfinfolen] = 0; | ||
| 554 | |||
| 472 | /* Parse USER@HOST.PID:BOOT_TIME. If can't parse, return -1. */ | 555 | /* Parse USER@HOST.PID:BOOT_TIME. If can't parse, return -1. */ |
| 473 | /* The USER is everything before the last @. */ | 556 | /* The USER is everything before the last @. */ |
| 474 | at = strrchr (lfinfo, '@'); | 557 | owner->at = at = memrchr (owner->user, '@', lfinfolen); |
| 475 | dot = strrchr (lfinfo, '.'); | 558 | if (!at) |
| 476 | if (!at || !dot) | 559 | return -1; |
| 560 | owner->dot = dot = strrchr (at, '.'); | ||
| 561 | if (!dot) | ||
| 477 | return -1; | 562 | return -1; |
| 478 | len = at - lfinfo; | ||
| 479 | GCPRO1 (lfinfo_object); | ||
| 480 | owner->user = xmalloc (len + 1); | ||
| 481 | memcpy (owner->user, lfinfo, len); | ||
| 482 | owner->user[len] = 0; | ||
| 483 | 563 | ||
| 484 | /* The PID is everything from the last `.' to the `:'. */ | 564 | /* The PID is everything from the last `.' to the `:'. */ |
| 565 | if (! c_isdigit (dot[1])) | ||
| 566 | return -1; | ||
| 485 | errno = 0; | 567 | errno = 0; |
| 486 | n = strtoimax (dot + 1, NULL, 10); | 568 | pid = strtoimax (dot + 1, &owner->colon, 10); |
| 487 | owner->pid = | 569 | if (errno == ERANGE) |
| 488 | ((0 <= n && n <= TYPE_MAXIMUM (pid_t) | 570 | pid = -1; |
| 489 | && (TYPE_MAXIMUM (pid_t) < INTMAX_MAX || errno != ERANGE)) | ||
| 490 | ? n : 0); | ||
| 491 | 571 | ||
| 492 | colon = strchr (dot + 1, ':'); | ||
| 493 | /* After the `:', if there is one, comes the boot time. */ | 572 | /* After the `:', if there is one, comes the boot time. */ |
| 494 | n = 0; | 573 | switch (owner->colon[0]) |
| 495 | if (colon) | ||
| 496 | { | 574 | { |
| 497 | errno = 0; | 575 | case 0: |
| 498 | n = strtoimax (colon + 1, NULL, 10); | 576 | boot_time = 0; |
| 577 | lfinfo_end = owner->colon; | ||
| 578 | break; | ||
| 579 | |||
| 580 | case ':': | ||
| 581 | if (! c_isdigit (owner->colon[1])) | ||
| 582 | return -1; | ||
| 583 | boot_time = strtoimax (owner->colon + 1, &lfinfo_end, 10); | ||
| 584 | break; | ||
| 585 | |||
| 586 | default: | ||
| 587 | return -1; | ||
| 499 | } | 588 | } |
| 500 | owner->boot_time = | 589 | if (lfinfo_end != owner->user + lfinfolen) |
| 501 | ((0 <= n && n <= TYPE_MAXIMUM (time_t) | 590 | return -1; |
| 502 | && (TYPE_MAXIMUM (time_t) < INTMAX_MAX || errno != ERANGE)) | ||
| 503 | ? n : 0); | ||
| 504 | |||
| 505 | /* The host is everything in between. */ | ||
| 506 | len = dot - at - 1; | ||
| 507 | owner->host = xmalloc (len + 1); | ||
| 508 | memcpy (owner->host, at + 1, len); | ||
| 509 | owner->host[len] = 0; | ||
| 510 | |||
| 511 | /* We're done looking at the link info. */ | ||
| 512 | UNGCPRO; | ||
| 513 | 591 | ||
| 514 | /* On current host? */ | 592 | /* On current host? */ |
| 515 | if (STRINGP (Fsystem_name ()) | 593 | if (STRINGP (Vsystem_name) |
| 516 | && strcmp (owner->host, SSDATA (Fsystem_name ())) == 0) | 594 | && dot - (at + 1) == SBYTES (Vsystem_name) |
| 595 | && memcmp (at + 1, SSDATA (Vsystem_name), SBYTES (Vsystem_name)) == 0) | ||
| 517 | { | 596 | { |
| 518 | if (owner->pid == getpid ()) | 597 | if (pid == getpid ()) |
| 519 | ret = 2; /* We own it. */ | 598 | ret = 2; /* We own it. */ |
| 520 | else if (owner->pid > 0 | 599 | else if (0 < pid && pid <= TYPE_MAXIMUM (pid_t) |
| 521 | && (kill (owner->pid, 0) >= 0 || errno == EPERM) | 600 | && (kill (pid, 0) >= 0 || errno == EPERM) |
| 522 | && (owner->boot_time == 0 | 601 | && (boot_time == 0 |
| 523 | || within_one_second (owner->boot_time, get_boot_time ()))) | 602 | || (boot_time <= TYPE_MAXIMUM (time_t) |
| 603 | && within_one_second (boot_time, get_boot_time ())))) | ||
| 524 | ret = 1; /* An existing process on this machine owns it. */ | 604 | ret = 1; /* An existing process on this machine owns it. */ |
| 525 | /* The owner process is dead or has a strange pid (<=0), so try to | 605 | /* The owner process is dead or has a strange pid, so try to |
| 526 | zap the lockfile. */ | 606 | zap the lockfile. */ |
| 527 | else if (unlink (lfname) < 0) | ||
| 528 | ret = -1; | ||
| 529 | else | 607 | else |
| 530 | ret = 0; | 608 | return unlink (lfname); |
| 531 | } | 609 | } |
| 532 | else | 610 | else |
| 533 | { /* If we wanted to support the check for stale locks on remote machines, | 611 | { /* If we wanted to support the check for stale locks on remote machines, |
| @@ -535,11 +613,6 @@ current_lock_owner (lock_info_type *owner, char *lfname) | |||
| 535 | ret = 1; | 613 | ret = 1; |
| 536 | } | 614 | } |
| 537 | 615 | ||
| 538 | /* Avoid garbage. */ | ||
| 539 | if (owner == &local_owner || ret <= 0) | ||
| 540 | { | ||
| 541 | FREE_LOCK_INFO (*owner); | ||
| 542 | } | ||
| 543 | return ret; | 616 | return ret; |
| 544 | } | 617 | } |
| 545 | 618 | ||
| @@ -551,29 +624,25 @@ current_lock_owner (lock_info_type *owner, char *lfname) | |||
| 551 | Return -1 if cannot lock for any other reason. */ | 624 | Return -1 if cannot lock for any other reason. */ |
| 552 | 625 | ||
| 553 | static int | 626 | static int |
| 554 | lock_if_free (lock_info_type *clasher, register char *lfname) | 627 | lock_if_free (lock_info_type *clasher, char *lfname) |
| 555 | { | 628 | { |
| 556 | while (! lock_file_1 (lfname, 0)) | 629 | int err; |
| 630 | while ((err = lock_file_1 (lfname, 0)) == EEXIST) | ||
| 557 | { | 631 | { |
| 558 | int locker; | 632 | switch (current_lock_owner (clasher, lfname)) |
| 559 | 633 | { | |
| 560 | if (errno != EEXIST) | 634 | case 2: |
| 561 | return -1; | 635 | return 0; /* We ourselves locked it. */ |
| 562 | 636 | case 1: | |
| 563 | locker = current_lock_owner (clasher, lfname); | 637 | return 1; /* Someone else has it. */ |
| 564 | if (locker == 2) | 638 | case -1: |
| 565 | { | 639 | return -1; /* current_lock_owner returned strange error. */ |
| 566 | FREE_LOCK_INFO (*clasher); | 640 | } |
| 567 | return 0; /* We ourselves locked it. */ | ||
| 568 | } | ||
| 569 | else if (locker == 1) | ||
| 570 | return 1; /* Someone else has it. */ | ||
| 571 | else if (locker == -1) | ||
| 572 | return -1; /* current_lock_owner returned strange error. */ | ||
| 573 | 641 | ||
| 574 | /* We deleted a stale lock; try again to lock the file. */ | 642 | /* We deleted a stale lock; try again to lock the file. */ |
| 575 | } | 643 | } |
| 576 | return 0; | 644 | |
| 645 | return err ? -1 : 0; | ||
| 577 | } | 646 | } |
| 578 | 647 | ||
| 579 | /* lock_file locks file FN, | 648 | /* lock_file locks file FN, |
| @@ -645,17 +714,16 @@ lock_file (Lisp_Object fn) | |||
| 645 | if (0 < lock_if_free (&lock_info, lfname)) | 714 | if (0 < lock_if_free (&lock_info, lfname)) |
| 646 | { | 715 | { |
| 647 | /* Someone else has the lock. Consider breaking it. */ | 716 | /* Someone else has the lock. Consider breaking it. */ |
| 648 | ptrdiff_t locker_size = (strlen (lock_info.user) + strlen (lock_info.host) | ||
| 649 | + INT_STRLEN_BOUND (printmax_t) | ||
| 650 | + sizeof "@ (pid )"); | ||
| 651 | char *locker = SAFE_ALLOCA (locker_size); | ||
| 652 | printmax_t pid = lock_info.pid; | ||
| 653 | Lisp_Object attack; | 717 | Lisp_Object attack; |
| 654 | esprintf (locker, "%s@%s (pid %"pMd")", | 718 | char *dot = lock_info.dot; |
| 655 | lock_info.user, lock_info.host, pid); | 719 | ptrdiff_t pidlen = lock_info.colon - (dot + 1); |
| 656 | FREE_LOCK_INFO (lock_info); | 720 | static char const replacement[] = " (pid "; |
| 657 | 721 | int replacementlen = sizeof replacement - 1; | |
| 658 | attack = call2 (intern ("ask-user-about-lock"), fn, build_string (locker)); | 722 | memmove (dot + replacementlen, dot + 1, pidlen); |
| 723 | strcpy (dot + replacementlen + pidlen, ")"); | ||
| 724 | memcpy (dot, replacement, replacementlen); | ||
| 725 | attack = call2 (intern ("ask-user-about-lock"), fn, | ||
| 726 | build_string (lock_info.user)); | ||
| 659 | /* Take the lock if the user said so. */ | 727 | /* Take the lock if the user said so. */ |
| 660 | if (!NILP (attack)) | 728 | if (!NILP (attack)) |
| 661 | lock_file_1 (lfname, 1); | 729 | lock_file_1 (lfname, 1); |
| @@ -760,10 +828,7 @@ t if it is locked by you, else a string saying which user has locked it. */) | |||
| 760 | else if (owner == 2) | 828 | else if (owner == 2) |
| 761 | ret = Qt; | 829 | ret = Qt; |
| 762 | else | 830 | else |
| 763 | ret = build_string (locker.user); | 831 | ret = make_string (locker.user, locker.at - locker.user); |
| 764 | |||
| 765 | if (owner > 0) | ||
| 766 | FREE_LOCK_INFO (locker); | ||
| 767 | 832 | ||
| 768 | SAFE_FREE (); | 833 | SAFE_FREE (); |
| 769 | return ret; | 834 | return ret; |