80 |
#ifndef WTMP_FILE |
#ifndef WTMP_FILE |
81 |
#define WTMP_FILE "/var/log/wtmp" |
#define WTMP_FILE "/var/log/wtmp" |
82 |
#endif |
#endif |
83 |
|
|
84 |
/* The strategy: to lock a file FN, create a symlink .#FN in FN's |
/* The strategy: to lock a file FN, create a symlink .#FN in FN's |
85 |
directory, with link data `user@host.pid'. This avoids a single |
directory, with link data `user@host.pid'. This avoids a single |
86 |
mount (== failure) point for lock files. |
mount (== failure) point for lock files. |
87 |
|
|
88 |
When the host in the lock data is the current host, we can check if |
When the host in the lock data is the current host, we can check if |
89 |
the pid is valid with kill. |
the pid is valid with kill. |
90 |
|
|
91 |
Otherwise, we could look at a separate file that maps hostnames to |
Otherwise, we could look at a separate file that maps hostnames to |
92 |
reboot times to see if the remote pid can possibly be valid, since we |
reboot times to see if the remote pid can possibly be valid, since we |
93 |
don't want Emacs to have to communicate via pipes or sockets or |
don't want Emacs to have to communicate via pipes or sockets or |
105 |
files to be useful on old systems lacking symlinks, nowadays |
files to be useful on old systems lacking symlinks, nowadays |
106 |
virtually all such systems are probably single-user anyway, so it |
virtually all such systems are probably single-user anyway, so it |
107 |
didn't seem worth the complication. |
didn't seem worth the complication. |
108 |
|
|
109 |
Similarly, we don't worry about a possible 14-character limit on |
Similarly, we don't worry about a possible 14-character limit on |
110 |
file names, because those are all the same systems that don't have |
file names, because those are all the same systems that don't have |
111 |
symlinks. |
symlinks. |
112 |
|
|
113 |
This is compatible with the locking scheme used by Interleaf (which |
This is compatible with the locking scheme used by Interleaf (which |
114 |
has contributed this implementation for Emacs), and was designed by |
has contributed this implementation for Emacs), and was designed by |
115 |
Ethan Jacobson, Kimbo Mundy, and others. |
Ethan Jacobson, Kimbo Mundy, and others. |
116 |
|
|
117 |
--karl@cs.umb.edu/karl@hq.ileaf.com. */ |
--karl@cs.umb.edu/karl@hq.ileaf.com. */ |
118 |
|
|
119 |
|
|
344 |
do something to support 14-character-max file names. */ |
do something to support 14-character-max file names. */ |
345 |
for (p = lockfile + strlen (lockfile); p != lockfile && *p != '/'; p--) |
for (p = lockfile + strlen (lockfile); p != lockfile && *p != '/'; p--) |
346 |
p[2] = *p; |
p[2] = *p; |
347 |
|
|
348 |
/* Insert the `.#'. */ |
/* Insert the `.#'. */ |
349 |
p[1] = '.'; |
p[1] = '.'; |
350 |
p[2] = '#'; |
p[2] = '#'; |
368 |
|
|
369 |
static int |
static int |
370 |
lock_file_1 (lfname, force) |
lock_file_1 (lfname, force) |
371 |
char *lfname; |
char *lfname; |
372 |
int force; |
int force; |
373 |
{ |
{ |
374 |
register int err; |
register int err; |
394 |
(unsigned long) getpid (), (unsigned long) boot_time); |
(unsigned long) getpid (), (unsigned long) boot_time); |
395 |
else |
else |
396 |
sprintf (lock_info_str, "%s@%s.%lu", user_name, host_name, |
sprintf (lock_info_str, "%s@%s.%lu", user_name, host_name, |
397 |
(unsigned long) getpid ()); |
(unsigned long) getpid ()); |
398 |
|
|
399 |
err = symlink (lock_info_str, lfname); |
err = symlink (lock_info_str, lfname); |
400 |
if (errno == EEXIST && force) |
if (errno == EEXIST && force) |
448 |
#endif |
#endif |
449 |
} |
} |
450 |
while (len >= bufsize); |
while (len >= bufsize); |
451 |
|
|
452 |
/* If nonexistent lock file, all is well; otherwise, got strange error. */ |
/* If nonexistent lock file, all is well; otherwise, got strange error. */ |
453 |
if (len == -1) |
if (len == -1) |
454 |
{ |
{ |
458 |
|
|
459 |
/* Link info exists, so `len' is its length. Null terminate. */ |
/* Link info exists, so `len' is its length. Null terminate. */ |
460 |
lfinfo[len] = 0; |
lfinfo[len] = 0; |
461 |
|
|
462 |
/* Even if the caller doesn't want the owner info, we still have to |
/* Even if the caller doesn't want the owner info, we still have to |
463 |
read it to determine return value, so allocate it. */ |
read it to determine return value, so allocate it. */ |
464 |
if (!owner) |
if (!owner) |
466 |
owner = (lock_info_type *) alloca (sizeof (lock_info_type)); |
owner = (lock_info_type *) alloca (sizeof (lock_info_type)); |
467 |
local_owner = 1; |
local_owner = 1; |
468 |
} |
} |
469 |
|
|
470 |
/* Parse USER@HOST.PID:BOOT_TIME. If can't parse, return -1. */ |
/* Parse USER@HOST.PID:BOOT_TIME. If can't parse, return -1. */ |
471 |
/* The USER is everything before the first @. */ |
/* The USER is everything before the first @. */ |
472 |
at = index (lfinfo, '@'); |
at = index (lfinfo, '@'); |
480 |
owner->user = (char *) xmalloc (len + 1); |
owner->user = (char *) xmalloc (len + 1); |
481 |
strncpy (owner->user, lfinfo, len); |
strncpy (owner->user, lfinfo, len); |
482 |
owner->user[len] = 0; |
owner->user[len] = 0; |
483 |
|
|
484 |
/* The PID is everything from the last `.' to the `:'. */ |
/* The PID is everything from the last `.' to the `:'. */ |
485 |
owner->pid = atoi (dot + 1); |
owner->pid = atoi (dot + 1); |
486 |
colon = dot; |
colon = dot; |
500 |
|
|
501 |
/* We're done looking at the link info. */ |
/* We're done looking at the link info. */ |
502 |
xfree (lfinfo); |
xfree (lfinfo); |
503 |
|
|
504 |
/* On current host? */ |
/* On current host? */ |
505 |
if (STRINGP (Fsystem_name ()) |
if (STRINGP (Fsystem_name ()) |
506 |
&& strcmp (owner->host, SDATA (Fsystem_name ())) == 0) |
&& strcmp (owner->host, SDATA (Fsystem_name ())) == 0) |
524 |
here's where we'd do it. */ |
here's where we'd do it. */ |
525 |
ret = 1; |
ret = 1; |
526 |
} |
} |
527 |
|
|
528 |
/* Avoid garbage. */ |
/* Avoid garbage. */ |
529 |
if (local_owner || ret <= 0) |
if (local_owner || ret <= 0) |
530 |
{ |
{ |
543 |
static int |
static int |
544 |
lock_if_free (clasher, lfname) |
lock_if_free (clasher, lfname) |
545 |
lock_info_type *clasher; |
lock_info_type *clasher; |
546 |
register char *lfname; |
register char *lfname; |
547 |
{ |
{ |
548 |
while (lock_file_1 (lfname, 0) == 0) |
while (lock_file_1 (lfname, 0) == 0) |
549 |
{ |
{ |
551 |
|
|
552 |
if (errno != EEXIST) |
if (errno != EEXIST) |
553 |
return -1; |
return -1; |
554 |
|
|
555 |
locker = current_lock_owner (clasher, lfname); |
locker = current_lock_owner (clasher, lfname); |
556 |
if (locker == 2) |
if (locker == 2) |
557 |
{ |
{ |
634 |
sprintf (locker, "%s@%s (pid %lu)", lock_info.user, lock_info.host, |
sprintf (locker, "%s@%s (pid %lu)", lock_info.user, lock_info.host, |
635 |
lock_info.pid); |
lock_info.pid); |
636 |
FREE_LOCK_INFO (lock_info); |
FREE_LOCK_INFO (lock_info); |
637 |
|
|
638 |
attack = call2 (intern ("ask-user-about-lock"), fn, build_string (locker)); |
attack = call2 (intern ("ask-user-about-lock"), fn, build_string (locker)); |
639 |
if (!NILP (attack)) |
if (!NILP (attack)) |
640 |
/* User says take the lock */ |
/* User says take the lock */ |
691 |
if (SAVE_MODIFF < MODIFF |
if (SAVE_MODIFF < MODIFF |
692 |
&& !NILP (file)) |
&& !NILP (file)) |
693 |
lock_file (file); |
lock_file (file); |
694 |
return Qnil; |
return Qnil; |
695 |
} |
} |
696 |
|
|
697 |
DEFUN ("unlock-buffer", Funlock_buffer, Sunlock_buffer, |
DEFUN ("unlock-buffer", Funlock_buffer, Sunlock_buffer, |