Merge remote-tracking branch 'origin/master' into for-steve
[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, max_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         max_sz = strlen(lock_info.user) + strlen(lock_info.host)
335                 + LOCK_PID_MAX + 9;
336         locker = (char *)alloca(max_sz);
337         sz = snprintf(locker, max_sz, "%s@%s (pid %lu)",
338                       lock_info.user, lock_info.host,
339                       lock_info.pid);
340         assert(sz>=0 && sz < max_sz);
341         FREE_LOCK_INFO(lock_info);
342
343         attack = call2_in_buffer(BUFFERP(subject_buf) ? XBUFFER(subject_buf) :
344                                  current_buffer, Qask_user_about_lock, fn,
345                                  build_string(locker));
346         if (!NILP(attack) && current_buffer == XBUFFER(old_current_buffer))
347                 /* User says take the lock */
348         {
349                 lock_file_1(lfname, 1);
350                 goto done;
351         }
352         /* User says ignore the lock */
353       done:
354         UNGCPRO;
355 }
356
357 void unlock_file(Lisp_Object fn)
358 {
359         /* This can GC */
360         register char *lfname;
361         struct gcpro gcpro1;
362
363         GCPRO1(fn);
364
365         fn = Fexpand_file_name(fn, Qnil);
366
367         MAKE_LOCK_NAME(lfname, fn);
368
369         if (current_lock_owner(0, lfname) == 2)
370                 unlink(lfname);
371
372         UNGCPRO;
373 }
374
375 void unlock_all_files(void)
376 {
377         register Lisp_Object tail;
378
379         for (tail = Vbuffer_alist; CONSP(tail); tail = XCDR(tail)) {
380                 struct buffer *b = XBUFFER(XCDR(XCAR(tail)));
381                 if (STRINGP(b->file_truename)
382                     && BUF_SAVE_MODIFF(b) < BUF_MODIFF(b))
383                         unlock_file(b->file_truename);
384         }
385 }
386 \f
387 DEFUN("lock-buffer", Flock_buffer, 0, 1, 0,     /*
388 Lock FILE, if current buffer is modified.
389 FILE defaults to current buffer's visited file,
390 or else nothing is done if current buffer isn't visiting a file.
391 */
392       (file))
393 {
394         if (NILP(file))
395                 file = current_buffer->file_truename;
396         CHECK_STRING(file);
397         if (BUF_SAVE_MODIFF(current_buffer) < BUF_MODIFF(current_buffer)
398             && !NILP(file))
399                 lock_file(file);
400         return Qnil;
401 }
402
403 DEFUN("unlock-buffer", Funlock_buffer, 0, 0, 0, /*
404 Unlock the file visited in the current buffer,
405 if it should normally be locked.
406 */
407       ())
408 {
409         /* This function can GC */
410         /* dmoore - and can destroy current_buffer and all sorts of other
411            mean nasty things with pointy teeth.  If you call this make sure
412            you protect things right. */
413
414         if (BUF_SAVE_MODIFF(current_buffer) < BUF_MODIFF(current_buffer)
415             && STRINGP(current_buffer->file_truename))
416                 unlock_file(current_buffer->file_truename);
417         return Qnil;
418 }
419
420 /* Unlock the file visited in buffer BUFFER.  */
421
422 void unlock_buffer(struct buffer *buffer)
423 {
424         /* This function can GC */
425         /* dmoore - and can destroy current_buffer and all sorts of other
426            mean nasty things with pointy teeth.  If you call this make sure
427            you protect things right. */
428         if (BUF_SAVE_MODIFF(buffer) < BUF_MODIFF(buffer)
429             && STRINGP(buffer->file_truename))
430                 unlock_file(buffer->file_truename);
431 }
432
433 DEFUN("file-locked-p", Ffile_locked_p, 0, 1, 0, /*
434 Return nil if the FILENAME is not locked,
435 t if it is locked by you, else a string of the name of the locker.
436 */
437       (filename))
438 {
439         Lisp_Object ret;
440         register char *lfname;
441         int owner;
442         lock_info_type locker;
443         struct gcpro gcpro1;
444
445         GCPRO1(filename);
446
447         filename = Fexpand_file_name(filename, Qnil);
448
449         MAKE_LOCK_NAME(lfname, filename);
450
451         owner = current_lock_owner(&locker, lfname);
452         if (owner <= 0)
453                 ret = Qnil;
454         else if (owner == 2)
455                 ret = Qt;
456         else
457                 ret = build_string(locker.user);
458
459         if (owner > 0)
460                 FREE_LOCK_INFO(locker);
461
462         UNGCPRO;
463
464         return ret;
465 }
466 \f
467 /* Initialization functions.  */
468
469 void syms_of_filelock(void)
470 {
471         /* This function can GC */
472         DEFSUBR(Funlock_buffer);
473         DEFSUBR(Flock_buffer);
474         DEFSUBR(Ffile_locked_p);
475
476         defsymbol(&Qask_user_about_supersession_threat,
477                   "ask-user-about-supersession-threat");
478         defsymbol(&Qask_user_about_lock, "ask-user-about-lock");
479 }
480
481 void vars_of_filelock(void)
482 {
483         DEFVAR_BOOL("inhibit-clash-detection", &inhibit_clash_detection /*
484 Non-nil inhibits creation of lock file to detect clash.
485                                                                          */ );
486         inhibit_clash_detection = 0;
487 }
488
489 #endif                          /* CLASH_DETECTION */