Wand updates from Evgeny
[sxemacs] / src / filelock.c
1 /* Copyright (C) 1985, 86, 87, 93, 94, 96 Free Software Foundation, Inc.
2
3 This file is part of SXEmacs
4
5 SXEmacs is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 SXEmacs is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
17
18
19 /* Synced with FSF 20.2 */
20
21 #include <config.h>
22 #include "lisp.h"
23
24 #include "buffer.h"
25 #include <sxe-paths.h>
26
27 #include "sysfile.h"
28 #include "sysdir.h"
29 #include "syspwd.h"
30 #include "syssignal.h"          /* for kill */
31
32 Lisp_Object Qask_user_about_supersession_threat;
33 Lisp_Object Qask_user_about_lock;
34 int inhibit_clash_detection;
35
36 #ifdef CLASH_DETECTION
37
38 /* The strategy: to lock a file FN, create a symlink .#FN in FN's
39    directory, with link data `user@host.pid'.  This avoids a single
40    mount (== failure) point for lock files.
41
42    When the host in the lock data is the current host, we can check if
43    the pid is valid with kill.
44
45    Otherwise, we could look at a separate file that maps hostnames to
46    reboot times to see if the remote pid can possibly be valid, since we
47    don't want Emacs to have to communicate via pipes or sockets or
48    whatever to other processes, either locally or remotely; rms says
49    that's too unreliable.  Hence the separate file, which could
50    theoretically be updated by daemons running separately -- but this
51    whole idea is unimplemented; in practice, at least in our
52    environment, it seems such stale locks arise fairly infrequently, and
53    Emacs' standard methods of dealing with clashes suffice.
54
55    We use symlinks instead of normal files because (1) they can be
56    stored more efficiently on the filesystem, since the kernel knows
57    they will be small, and (2) all the info about the lock can be read
58    in a single system call (readlink).  Although we could use regular
59    files to be useful on old systems lacking symlinks, nowadays
60    virtually all such systems are probably single-user anyway, so it
61    didn't seem worth the complication.
62
63    Similarly, we don't worry about a possible 14-character limit on
64    file names, because those are all the same systems that don't have
65    symlinks.
66
67    This is compatible with the locking scheme used by Interleaf (which
68    has contributed this implementation for Emacs), and was designed by
69    Ethan Jacobson, Kimbo Mundy, and others.
70
71    --karl@cs.umb.edu/karl@hq.ileaf.com.  */
72
73 /* Note that muleization is provided by using mule-encapsulated
74    versions of the system calls we use like symlink(), unlink(), etc... */
75 \f
76 /* Here is the structure that stores information about a lock.  */
77
78 typedef struct {
79         char *user;
80         char *host;
81         unsigned long pid;
82 } lock_info_type;
83
84 /* When we read the info back, we might need this much more,
85    enough for decimal representation plus null.  */
86 #define LOCK_PID_MAX (4 * sizeof (unsigned long))
87
88 /* Free the two dynamically-allocated pieces in PTR.  */
89 #define FREE_LOCK_INFO(i) do { xfree ((i).user); xfree ((i).host); } while (0)
90
91 /* Write the name of the lock file for FN into LFNAME.  Length will be
92    that of FN plus two more for the leading `.#' plus one for the null.  */
93 #define MAKE_LOCK_NAME(lock, file) \
94   (lock = (char *) alloca (XSTRING_LENGTH (file) + 2 + 1), \
95    fill_in_lock_file_name ((Bufbyte *) (lock), (file)))
96
97 static void fill_in_lock_file_name(Bufbyte * lockfile, Lisp_Object fn)
98 {
99         Bufbyte *file_name = XSTRING_DATA(fn);
100         Bufbyte *p;
101         size_t dirlen;
102
103         for (p = file_name + XSTRING_LENGTH(fn) - 1;
104              p > file_name && !IS_ANY_SEP(p[-1]); p--) ;
105         dirlen = p - file_name;
106
107         memcpy(lockfile, file_name, dirlen);
108         p = lockfile + dirlen;
109         *(p++) = '.';
110         *(p++) = '#';
111         memcpy(p, file_name + dirlen, XSTRING_LENGTH(fn) - dirlen + 1);
112 }
113
114 /* Lock the lock file named LFNAME.
115    If FORCE is nonzero, we do so even if it is already locked.
116    Return 1 if successful, 0 if not.  */
117
118 static int lock_file_1(char *lfname, int force)
119 {
120         /* Does not GC. */
121         int err;
122         char *lock_info_str;
123         char *host_name;
124         char *user_name = user_login_name(NULL);
125         int sz, maxlen;
126
127         if (user_name == NULL)
128                 user_name = "";
129
130         if (STRINGP(Vsystem_name))
131                 host_name = (char *)XSTRING_DATA(Vsystem_name);
132         else
133                 host_name = "";
134
135         maxlen = strlen(user_name) + strlen(host_name)
136                 + LOCK_PID_MAX + 5;
137         lock_info_str = (char *)alloca(maxlen);
138
139         sz = snprintf(lock_info_str, maxlen, "%s@%s.%lu", user_name, host_name,
140                       (unsigned long)getpid());
141         assert(sz>=0 && sz < maxlen);
142
143         err = symlink(lock_info_str, lfname);
144         if (err != 0 && errno == EEXIST && force) {
145                 unlink(lfname);
146                 err = symlink(lock_info_str, lfname);
147         }
148
149         return err == 0;
150 }
151 \f
152 /* Return 0 if nobody owns the lock file LFNAME or the lock is obsolete,
153    1 if another process owns it (and set OWNER (if non-null) to info),
154    2 if the current process owns it,
155    or -1 if something is wrong with the locking mechanism.  */
156
157 static int current_lock_owner(lock_info_type * owner, char *lfname)
158 {
159         /* Does not GC. */
160         int len, ret;
161         int local_owner = 0;
162         char *at, *dot;
163         char *lfinfo = 0;
164         int bufsize = 50;
165         /* Read arbitrarily-long contents of symlink.  Similar code in
166            file-symlink-p in fileio.c.  */
167         do {
168                 bufsize *= 2;
169                 lfinfo = (char *)xrealloc(lfinfo, bufsize);
170                 len = readlink(lfname, lfinfo, bufsize);
171         }
172         while (len >= bufsize);
173
174         /* If nonexistent lock file, all is well; otherwise, got strange error. */
175         if (len == -1) {
176                 xfree(lfinfo);
177                 return errno == ENOENT ? 0 : -1;
178         }
179
180         /* Link info exists, so `len' is its length.  Null terminate.  */
181         lfinfo[len] = 0;
182
183         /* Even if the caller doesn't want the owner info, we still have to
184            read it to determine return value, so allocate it.  */
185         if (!owner) {
186                 owner = (lock_info_type *) alloca(sizeof(lock_info_type));
187                 local_owner = 1;
188         }
189
190         /* Parse USER@HOST.PID.  If can't parse, return -1.  */
191         /* The USER is everything before the first @.  */
192         at = strchr(lfinfo, '@');
193         dot = strrchr(lfinfo, '.');
194         if (!at || !dot) {
195                 xfree(lfinfo);
196                 return -1;
197         }
198         len = at - lfinfo;
199         owner->user = (char *)xmalloc_atomic(len + 1);
200         strncpy(owner->user, lfinfo, len);
201         owner->user[len] = 0;
202
203         /* The PID is everything after the last `.'.  */
204         owner->pid = atoi(dot + 1);
205
206         /* The host is everything in between.  */
207         len = dot - at - 1;
208         owner->host = (char *)xmalloc_atomic(len + 1);
209         strncpy(owner->host, at + 1, len);
210         owner->host[len] = 0;
211
212         /* We're done looking at the link info.  */
213         xfree(lfinfo);
214
215         /* On current host?  */
216         if (STRINGP(Fsystem_name())
217             && strcmp(owner->host, (char *)XSTRING_DATA(Fsystem_name())) == 0) {
218                 if (owner->pid == (unsigned long)getpid())
219                         ret = 2;        /* We own it.  */
220                 else if (owner->pid > 0
221                          && (kill(owner->pid, 0) >= 0 || errno == EPERM))
222                         ret = 1;        /* An existing process on this machine owns it.  */
223                 /* The owner process is dead or has a strange pid (<=0), so try to
224                    zap the lockfile.  */
225                 else if (unlink(lfname) < 0)
226                         ret = -1;
227                 else
228                         ret = 0;
229         } else {                /* If we wanted to support the check for stale locks on remote machines,
230                                    here's where we'd do it.  */
231                 ret = 1;
232         }
233
234         /* Avoid garbage.  */
235         if (local_owner || ret <= 0) {
236                 FREE_LOCK_INFO(*owner);
237         }
238         return ret;
239 }
240 \f
241 /* Lock the lock named LFNAME if possible.
242    Return 0 in that case.
243    Return positive if some other process owns the lock, and info about
244      that process in CLASHER.
245    Return -1 if cannot lock for any other reason.  */
246
247 static int lock_if_free(lock_info_type * clasher, char *lfname)
248 {
249         /* Does not GC. */
250         if (lock_file_1(lfname, 0) == 0) {
251                 int locker;
252
253                 if (errno != EEXIST)
254                         return -1;
255
256                 locker = current_lock_owner(clasher, lfname);
257                 if (locker == 2) {
258                         FREE_LOCK_INFO(*clasher);
259                         return 0;       /* We ourselves locked it.  */
260                 } else if (locker == 1)
261                         return 1;       /* Someone else has it.  */
262
263                 return -1;      /* Something's wrong.  */
264         }
265         return 0;
266 }
267
268 /* lock_file locks file FN,
269    meaning it serves notice on the world that you intend to edit that file.
270    This should be done only when about to modify a file-visiting
271    buffer previously unmodified.
272    Do not (normally) call this for a buffer already modified,
273    as either the file is already locked, or the user has already
274    decided to go ahead without locking.
275
276    When this returns, either the lock is locked for us,
277    or the user has said to go ahead without locking.
278
279    If the file is locked by someone else, this calls
280    ask-user-about-lock (a Lisp function) with two arguments,
281    the file name and info about the user who did the locking.
282    This function can signal an error, or return t meaning
283    take away the lock, or return nil meaning ignore the lock.  */
284
285 void lock_file(Lisp_Object fn)
286 {
287         /* This function can GC.  GC checked 7-11-00 ben */
288         /* dmoore - and can destroy current_buffer and all sorts of other
289            mean nasty things with pointy teeth.  If you call this make sure
290            you protect things right. */
291         /* Somebody updated the code in this function and removed the previous
292            comment.  -slb */
293
294         register Lisp_Object attack, orig_fn;
295         register char *lfname, *locker;
296         lock_info_type lock_info;
297         struct gcpro gcpro1, gcpro2, gcpro3;
298         Lisp_Object old_current_buffer;
299         Lisp_Object subject_buf;
300         int sz;
301
302         if (inhibit_clash_detection)
303                 return;
304
305         XSETBUFFER(old_current_buffer, current_buffer);
306         subject_buf = Qnil;
307         GCPRO3(fn, subject_buf, old_current_buffer);
308         orig_fn = fn;
309         fn = Fexpand_file_name(fn, Qnil);
310
311         /* Create the name of the lock-file for file fn */
312         MAKE_LOCK_NAME(lfname, fn);
313
314         /* See if this file is visited and has changed on disk since it was
315            visited.  */
316         {
317                 subject_buf = get_truename_buffer(orig_fn);
318                 if (!NILP(subject_buf)
319                     && NILP(Fverify_visited_file_modtime(subject_buf))
320                     && !NILP(Ffile_exists_p(fn)))
321                         call1_in_buffer(XBUFFER(subject_buf),
322                                         Qask_user_about_supersession_threat,
323                                         fn);
324         }
325
326         /* Try to lock the lock. */
327         if (current_buffer != XBUFFER(old_current_buffer)
328             || lock_if_free(&lock_info, lfname) <= 0)
329                 /* Return now if we have locked it, or if lock creation failed
330                    or current buffer is killed. */
331                 goto done;
332
333         /* Else consider breaking the lock */
334         locker = (char *)alloca(strlen(lock_info.user) + strlen(lock_info.host)
335                                 + LOCK_PID_MAX + 9);
336         sz = snprintf(locker, sizeof(locker), "%s@%s (pid %lu)", 
337                       lock_info.user, lock_info.host,
338                       lock_info.pid);
339         assert(sz>=0 && sz < sizeof(locker));
340         FREE_LOCK_INFO(lock_info);
341
342         attack = call2_in_buffer(BUFFERP(subject_buf) ? XBUFFER(subject_buf) :
343                                  current_buffer, Qask_user_about_lock, fn,
344                                  build_string(locker));
345         if (!NILP(attack) && current_buffer == XBUFFER(old_current_buffer))
346                 /* User says take the lock */
347         {
348                 lock_file_1(lfname, 1);
349                 goto done;
350         }
351         /* User says ignore the lock */
352       done:
353         UNGCPRO;
354 }
355
356 void unlock_file(Lisp_Object fn)
357 {
358         /* This can GC */
359         register char *lfname;
360         struct gcpro gcpro1;
361
362         GCPRO1(fn);
363
364         fn = Fexpand_file_name(fn, Qnil);
365
366         MAKE_LOCK_NAME(lfname, fn);
367
368         if (current_lock_owner(0, lfname) == 2)
369                 unlink(lfname);
370
371         UNGCPRO;
372 }
373
374 void unlock_all_files(void)
375 {
376         register Lisp_Object tail;
377
378         for (tail = Vbuffer_alist; CONSP(tail); tail = XCDR(tail)) {
379                 struct buffer *b = XBUFFER(XCDR(XCAR(tail)));
380                 if (STRINGP(b->file_truename)
381                     && BUF_SAVE_MODIFF(b) < BUF_MODIFF(b))
382                         unlock_file(b->file_truename);
383         }
384 }
385 \f
386 DEFUN("lock-buffer", Flock_buffer, 0, 1, 0,     /*
387 Lock FILE, if current buffer is modified.
388 FILE defaults to current buffer's visited file,
389 or else nothing is done if current buffer isn't visiting a file.
390 */
391       (file))
392 {
393         if (NILP(file))
394                 file = current_buffer->file_truename;
395         CHECK_STRING(file);
396         if (BUF_SAVE_MODIFF(current_buffer) < BUF_MODIFF(current_buffer)
397             && !NILP(file))
398                 lock_file(file);
399         return Qnil;
400 }
401
402 DEFUN("unlock-buffer", Funlock_buffer, 0, 0, 0, /*
403 Unlock the file visited in the current buffer,
404 if it should normally be locked.
405 */
406       ())
407 {
408         /* This function can GC */
409         /* dmoore - and can destroy current_buffer and all sorts of other
410            mean nasty things with pointy teeth.  If you call this make sure
411            you protect things right. */
412
413         if (BUF_SAVE_MODIFF(current_buffer) < BUF_MODIFF(current_buffer)
414             && STRINGP(current_buffer->file_truename))
415                 unlock_file(current_buffer->file_truename);
416         return Qnil;
417 }
418
419 /* Unlock the file visited in buffer BUFFER.  */
420
421 void unlock_buffer(struct buffer *buffer)
422 {
423         /* This function can GC */
424         /* dmoore - and can destroy current_buffer and all sorts of other
425            mean nasty things with pointy teeth.  If you call this make sure
426            you protect things right. */
427         if (BUF_SAVE_MODIFF(buffer) < BUF_MODIFF(buffer)
428             && STRINGP(buffer->file_truename))
429                 unlock_file(buffer->file_truename);
430 }
431
432 DEFUN("file-locked-p", Ffile_locked_p, 0, 1, 0, /*
433 Return nil if the FILENAME is not locked,
434 t if it is locked by you, else a string of the name of the locker.
435 */
436       (filename))
437 {
438         Lisp_Object ret;
439         register char *lfname;
440         int owner;
441         lock_info_type locker;
442         struct gcpro gcpro1;
443
444         GCPRO1(filename);
445
446         filename = Fexpand_file_name(filename, Qnil);
447
448         MAKE_LOCK_NAME(lfname, filename);
449
450         owner = current_lock_owner(&locker, lfname);
451         if (owner <= 0)
452                 ret = Qnil;
453         else if (owner == 2)
454                 ret = Qt;
455         else
456                 ret = build_string(locker.user);
457
458         if (owner > 0)
459                 FREE_LOCK_INFO(locker);
460
461         UNGCPRO;
462
463         return ret;
464 }
465 \f
466 /* Initialization functions.  */
467
468 void syms_of_filelock(void)
469 {
470         /* This function can GC */
471         DEFSUBR(Funlock_buffer);
472         DEFSUBR(Flock_buffer);
473         DEFSUBR(Ffile_locked_p);
474
475         defsymbol(&Qask_user_about_supersession_threat,
476                   "ask-user-about-supersession-threat");
477         defsymbol(&Qask_user_about_lock, "ask-user-about-lock");
478 }
479
480 void vars_of_filelock(void)
481 {
482         DEFVAR_BOOL("inhibit-clash-detection", &inhibit_clash_detection /*
483 Non-nil inhibits creation of lock file to detect clash.
484                                                                          */ );
485         inhibit_clash_detection = 0;
486 }
487
488 #endif                          /* CLASH_DETECTION */