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 |
|
|
222 |
args[3] = Qnil; |
args[3] = Qnil; |
223 |
args[4] = build_string ("-c"); |
args[4] = build_string ("-c"); |
224 |
sprintf (cmd_string, "gunzip < %s.%d.gz > %s", |
sprintf (cmd_string, "gunzip < %s.%d.gz > %s", |
225 |
WTMP_FILE, counter, XSTRING (tempname)->data); |
WTMP_FILE, counter, SDATA (tempname)); |
226 |
args[5] = build_string (cmd_string); |
args[5] = build_string (cmd_string); |
227 |
Fcall_process (6, args); |
Fcall_process (6, args); |
228 |
filename = tempname; |
filename = tempname; |
232 |
|
|
233 |
if (! NILP (filename)) |
if (! NILP (filename)) |
234 |
{ |
{ |
235 |
get_boot_time_1 (XSTRING (filename)->data, 1); |
get_boot_time_1 (SDATA (filename), 1); |
236 |
if (delete_flag) |
if (delete_flag) |
237 |
unlink (XSTRING (filename)->data); |
unlink (SDATA (filename)); |
238 |
} |
} |
239 |
} |
} |
240 |
|
|
325 |
trailing period plus one for the digit after it plus one for the |
trailing period plus one for the digit after it plus one for the |
326 |
null. */ |
null. */ |
327 |
#define MAKE_LOCK_NAME(lock, file) \ |
#define MAKE_LOCK_NAME(lock, file) \ |
328 |
(lock = (char *) alloca (STRING_BYTES (XSTRING (file)) + 2 + 1 + 1 + 1), \ |
(lock = (char *) alloca (SBYTES (file) + 2 + 1 + 1 + 1), \ |
329 |
fill_in_lock_file_name (lock, (file))) |
fill_in_lock_file_name (lock, (file))) |
330 |
|
|
331 |
static void |
static void |
337 |
struct stat st; |
struct stat st; |
338 |
int count = 0; |
int count = 0; |
339 |
|
|
340 |
strcpy (lockfile, XSTRING (fn)->data); |
strcpy (lockfile, SDATA (fn)); |
341 |
|
|
342 |
/* Shift the nondirectory part of the file name (including the null) |
/* Shift the nondirectory part of the file name (including the null) |
343 |
right two characters. Here is one of the places where we'd have to |
right two characters. Here is one of the places where we'd have to |
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; |
378 |
char *lock_info_str; |
char *lock_info_str; |
379 |
|
|
380 |
if (STRINGP (Fuser_login_name (Qnil))) |
if (STRINGP (Fuser_login_name (Qnil))) |
381 |
user_name = (char *)XSTRING (Fuser_login_name (Qnil))->data; |
user_name = (char *)SDATA (Fuser_login_name (Qnil)); |
382 |
else |
else |
383 |
user_name = ""; |
user_name = ""; |
384 |
if (STRINGP (Fsystem_name ())) |
if (STRINGP (Fsystem_name ())) |
385 |
host_name = (char *)XSTRING (Fsystem_name ())->data; |
host_name = (char *)SDATA (Fsystem_name ()); |
386 |
else |
else |
387 |
host_name = ""; |
host_name = ""; |
388 |
lock_info_str = (char *)alloca (strlen (user_name) + strlen (host_name) |
lock_info_str = (char *)alloca (strlen (user_name) + strlen (host_name) |
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, XSTRING (Fsystem_name ())->data) == 0) |
&& strcmp (owner->host, SDATA (Fsystem_name ())) == 0) |
507 |
{ |
{ |
508 |
if (owner->pid == getpid ()) |
if (owner->pid == getpid ()) |
509 |
ret = 2; /* We own it. */ |
ret = 2; /* We own it. */ |
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, |