(describe_command): Use quotes around symbol name.
[bpt/emacs.git] / src / filelock.c
CommitLineData
8dbbc384 1/* Copyright (C) 1985, 86, 87, 93, 94, 96 Free Software Foundation, Inc.
8489eb67
RS
2
3This file is part of GNU Emacs.
4
5GNU Emacs is free software; you can redistribute it and/or modify
6it under the terms of the GNU General Public License as published by
32676c08 7the Free Software Foundation; either version 2, or (at your option)
8489eb67
RS
8any later version.
9
10GNU Emacs is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with GNU Emacs; see the file COPYING. If not, write to
3b7ad313
EN
17the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18Boston, MA 02111-1307, USA. */
8489eb67
RS
19
20
21#include <sys/types.h>
22#include <sys/stat.h>
18160b98 23#include <config.h>
bfb61299
JB
24
25#ifdef VMS
b350a838 26#include "vms-pwd.h"
bfb61299 27#else
8489eb67 28#include <pwd.h>
8dbbc384 29#endif /* not VMS */
bfb61299 30
8489eb67
RS
31#include <sys/file.h>
32#ifdef USG
33#include <fcntl.h>
8dbbc384 34#include <string.h>
8489eb67
RS
35#endif /* USG */
36
8489eb67 37#include "lisp.h"
8489eb67
RS
38#include "buffer.h"
39
15e88d21
RS
40#include <time.h>
41#include <utmp.h>
8dbbc384
RS
42#include <errno.h>
43#ifndef errno
8489eb67 44extern int errno;
79941276
RS
45#endif
46
8489eb67
RS
47#ifdef CLASH_DETECTION
48
8dbbc384
RS
49/* The strategy: to lock a file FN, create a symlink .#FN in FN's
50 directory, with link data `user@host.pid'. This avoids a single
51 mount (== failure) point for lock files.
52
53 When the host in the lock data is the current host, we can check if
54 the pid is valid with kill.
55
56 Otherwise, we could look at a separate file that maps hostnames to
57 reboot times to see if the remote pid can possibly be valid, since we
58 don't want Emacs to have to communicate via pipes or sockets or
59 whatever to other processes, either locally or remotely; rms says
60 that's too unreliable. Hence the separate file, which could
61 theoretically be updated by daemons running separately -- but this
62 whole idea is unimplemented; in practice, at least in our
1c4f857c 63 environment, it seems such stale locks arise fairly infrequently, and
8dbbc384
RS
64 Emacs' standard methods of dealing with clashes suffice.
65
66 We use symlinks instead of normal files because (1) they can be
67 stored more efficiently on the filesystem, since the kernel knows
68 they will be small, and (2) all the info about the lock can be read
69 in a single system call (readlink). Although we could use regular
1c4f857c 70 files to be useful on old systems lacking symlinks, nowadays
8dbbc384
RS
71 virtually all such systems are probably single-user anyway, so it
72 didn't seem worth the complication.
73
74 Similarly, we don't worry about a possible 14-character limit on
75 file names, because those are all the same systems that don't have
76 symlinks.
77
78 This is compatible with the locking scheme used by Interleaf (which
79 has contributed this implementation for Emacs), and was designed by
80 Ethan Jacobson, Kimbo Mundy, and others.
81
82 --karl@cs.umb.edu/karl@hq.ileaf.com. */
8489eb67 83
8dbbc384 84\f
15e88d21
RS
85/* Return the time of the last system boot. */
86
87static time_t boot_time;
88
89static time_t
90get_boot_time ()
91{
bd26d5a3 92#ifdef BOOT_TIME
15e88d21
RS
93 struct utmp ut, *utp;
94
95 if (boot_time)
96 return boot_time;
97
98 utmpname ("/var/log/wtmp");
99 ut.ut_type = BOOT_TIME;
100 utp = getutid (&ut);
101 endutent ();
102
103 if (!utp)
104 return boot_time = 1;
105 return boot_time = utp->ut_time;
bd26d5a3
RS
106#else
107 return 0;
108#endif;
15e88d21
RS
109}
110\f
8dbbc384 111/* Here is the structure that stores information about a lock. */
32676c08 112
8dbbc384
RS
113typedef struct
114{
115 char *user;
116 char *host;
9005cb4f 117 unsigned long pid;
15e88d21 118 time_t boot_time;
8dbbc384 119} lock_info_type;
32676c08 120
49b6d120
RS
121/* When we read the info back, we might need this much more,
122 enough for decimal representation plus null. */
123#define LOCK_PID_MAX (4 * sizeof (unsigned long))
32676c08 124
8dbbc384
RS
125/* Free the two dynamically-allocated pieces in PTR. */
126#define FREE_LOCK_INFO(i) do { xfree ((i).user); xfree ((i).host); } while (0)
e31fbc7a 127
e31fbc7a 128
8dbbc384
RS
129/* Write the name of the lock file for FN into LFNAME. Length will be
130 that of FN plus two more for the leading `.#' plus one for the null. */
7b92975f 131#define MAKE_LOCK_NAME(lock, file) \
fc932ac6 132 (lock = (char *) alloca (STRING_BYTES (XSTRING (file)) + 2 + 1), \
8dbbc384 133 fill_in_lock_file_name (lock, (file)))
e31fbc7a 134
8dbbc384
RS
135static void
136fill_in_lock_file_name (lockfile, fn)
e31fbc7a
RS
137 register char *lockfile;
138 register Lisp_Object fn;
139{
8dbbc384
RS
140 register char *p;
141
142 strcpy (lockfile, XSTRING (fn)->data);
143
144 /* Shift the nondirectory part of the file name (including the null)
145 right two characters. Here is one of the places where we'd have to
146 do something to support 14-character-max file names. */
147 for (p = lockfile + strlen (lockfile); p != lockfile && *p != '/'; p--)
148 p[2] = *p;
e31fbc7a 149
8dbbc384
RS
150 /* Insert the `.#'. */
151 p[1] = '.';
152 p[2] = '#';
153}
e31fbc7a 154
8dbbc384
RS
155/* Lock the lock file named LFNAME.
156 If FORCE is nonzero, we do so even if it is already locked.
157 Return 1 if successful, 0 if not. */
e31fbc7a 158
8dbbc384
RS
159static int
160lock_file_1 (lfname, force)
161 char *lfname;
162 int force;
163{
164 register int err;
bd26d5a3 165 time_t boot_time;
662c2ef2
RS
166 char *user_name;
167 char *host_name;
168 char *lock_info_str;
169
170 if (STRINGP (Fuser_login_name (Qnil)))
266d7a00 171 user_name = (char *)XSTRING (Fuser_login_name (Qnil))->data;
662c2ef2
RS
172 else
173 user_name = "";
174 if (STRINGP (Fsystem_name ()))
266d7a00 175 host_name = (char *)XSTRING (Fsystem_name ())->data;
662c2ef2
RS
176 else
177 host_name = "";
266d7a00 178 lock_info_str = (char *)alloca (strlen (user_name) + strlen (host_name)
15e88d21 179 + LOCK_PID_MAX + 5);
8dbbc384 180
bd26d5a3
RS
181 boot_time = get_boot_time ();
182 if (boot_time)
183 sprintf (lock_info_str, "%s@%s.%lu:%lu", user_name, host_name,
184 (unsigned long) getpid (), (unsigned long) boot_time);
185 else
186 sprintf (lock_info_str, "%s@%s.%lu", user_name, host_name,
187 (unsigned long) getpid ());
8dbbc384
RS
188
189 err = symlink (lock_info_str, lfname);
190 if (errno == EEXIST && force)
e31fbc7a 191 {
8dbbc384
RS
192 unlink (lfname);
193 err = symlink (lock_info_str, lfname);
e31fbc7a 194 }
e31fbc7a 195
8dbbc384
RS
196 return err == 0;
197}
e31fbc7a 198
32676c08 199
8dbbc384
RS
200\f
201/* Return 0 if nobody owns the lock file LFNAME or the lock is obsolete,
202 1 if another process owns it (and set OWNER (if non-null) to info),
203 2 if the current process owns it,
204 or -1 if something is wrong with the locking mechanism. */
e31fbc7a 205
8dbbc384
RS
206static int
207current_lock_owner (owner, lfname)
208 lock_info_type *owner;
209 char *lfname;
32676c08 210{
8dbbc384
RS
211#ifndef index
212 extern char *rindex (), *index ();
213#endif
214 int o, p, len, ret;
215 int local_owner = 0;
15e88d21 216 char *at, *dot, *colon;
8dbbc384
RS
217 char *lfinfo = 0;
218 int bufsize = 50;
219 /* Read arbitrarily-long contents of symlink. Similar code in
220 file-symlink-p in fileio.c. */
221 do
222 {
223 bufsize *= 2;
224 lfinfo = (char *) xrealloc (lfinfo, bufsize);
225 len = readlink (lfname, lfinfo, bufsize);
226 }
227 while (len >= bufsize);
228
229 /* If nonexistent lock file, all is well; otherwise, got strange error. */
230 if (len == -1)
231 {
232 xfree (lfinfo);
233 return errno == ENOENT ? 0 : -1;
234 }
32676c08 235
8dbbc384
RS
236 /* Link info exists, so `len' is its length. Null terminate. */
237 lfinfo[len] = 0;
238
239 /* Even if the caller doesn't want the owner info, we still have to
240 read it to determine return value, so allocate it. */
241 if (!owner)
242 {
3609a53b 243 owner = (lock_info_type *) alloca (sizeof (lock_info_type));
8dbbc384
RS
244 local_owner = 1;
245 }
246
15e88d21 247 /* Parse USER@HOST.PID:BOOT_TIME. If can't parse, return -1. */
8dbbc384
RS
248 /* The USER is everything before the first @. */
249 at = index (lfinfo, '@');
250 dot = rindex (lfinfo, '.');
15e88d21
RS
251 if (!at || !dot)
252 {
253 xfree (lfinfo);
254 return -1;
255 }
8dbbc384
RS
256 len = at - lfinfo;
257 owner->user = (char *) xmalloc (len + 1);
258 strncpy (owner->user, lfinfo, len);
259 owner->user[len] = 0;
260
15e88d21 261 /* The PID is everything from the last `.' to the `:'. */
8dbbc384 262 owner->pid = atoi (dot + 1);
15e88d21
RS
263 colon = dot;
264 while (*colon && *colon != ':')
265 colon++;
266 /* After the `:', if there is one, comes the boot time. */
267 if (*colon == ':')
268 owner->boot_time = atoi (colon + 1);
269 else
270 owner->boot_time = 0;
32676c08 271
8dbbc384
RS
272 /* The host is everything in between. */
273 len = dot - at - 1;
274 owner->host = (char *) xmalloc (len + 1);
275 strncpy (owner->host, at + 1, len);
276 owner->host[len] = 0;
32676c08 277
8dbbc384
RS
278 /* We're done looking at the link info. */
279 xfree (lfinfo);
280
281 /* On current host? */
662c2ef2
RS
282 if (STRINGP (Fsystem_name ())
283 && strcmp (owner->host, XSTRING (Fsystem_name ())->data) == 0)
32676c08 284 {
8dbbc384
RS
285 if (owner->pid == getpid ())
286 ret = 2; /* We own it. */
72dcef0e 287 else if (owner->pid > 0
15e88d21
RS
288 && (kill (owner->pid, 0) >= 0 || errno == EPERM)
289 && (owner->boot_time == 0
290 || owner->boot_time == get_boot_time ()))
8dbbc384 291 ret = 1; /* An existing process on this machine owns it. */
8dbbc384
RS
292 /* The owner process is dead or has a strange pid (<=0), so try to
293 zap the lockfile. */
72dcef0e 294 else if (unlink (lfname) < 0)
8dbbc384 295 ret = -1;
72dcef0e
RS
296 else
297 ret = 0;
32676c08 298 }
8dbbc384
RS
299 else
300 { /* If we wanted to support the check for stale locks on remote machines,
301 here's where we'd do it. */
302 ret = 1;
303 }
304
305 /* Avoid garbage. */
306 if (local_owner || ret <= 0)
307 {
308 FREE_LOCK_INFO (*owner);
309 }
310 return ret;
32676c08
JB
311}
312
8dbbc384
RS
313\f
314/* Lock the lock named LFNAME if possible.
315 Return 0 in that case.
316 Return positive if some other process owns the lock, and info about
317 that process in CLASHER.
318 Return -1 if cannot lock for any other reason. */
8489eb67 319
8dbbc384
RS
320static int
321lock_if_free (clasher, lfname)
322 lock_info_type *clasher;
323 register char *lfname;
324{
c6c0c4b1 325 if (lock_file_1 (lfname, 0) == 0)
8dbbc384
RS
326 {
327 int locker;
e0e0205b 328
8dbbc384
RS
329 if (errno != EEXIST)
330 return -1;
331
332 locker = current_lock_owner (clasher, lfname);
333 if (locker == 2)
334 {
335 FREE_LOCK_INFO (*clasher);
336 return 0; /* We ourselves locked it. */
337 }
338 else if (locker == 1)
339 return 1; /* Someone else has it. */
8dbbc384 340
c6c0c4b1 341 return -1; /* Something's wrong. */
8dbbc384
RS
342 }
343 return 0;
8489eb67
RS
344}
345
8dbbc384 346/* lock_file locks file FN,
8489eb67
RS
347 meaning it serves notice on the world that you intend to edit that file.
348 This should be done only when about to modify a file-visiting
349 buffer previously unmodified.
8dbbc384 350 Do not (normally) call this for a buffer already modified,
8489eb67
RS
351 as either the file is already locked, or the user has already
352 decided to go ahead without locking.
353
8dbbc384 354 When this returns, either the lock is locked for us,
8489eb67
RS
355 or the user has said to go ahead without locking.
356
8dbbc384 357 If the file is locked by someone else, this calls
8489eb67 358 ask-user-about-lock (a Lisp function) with two arguments,
8dbbc384 359 the file name and info about the user who did the locking.
8489eb67
RS
360 This function can signal an error, or return t meaning
361 take away the lock, or return nil meaning ignore the lock. */
362
8489eb67
RS
363void
364lock_file (fn)
8dbbc384 365 register Lisp_Object fn;
8489eb67 366{
5383bc6d 367 register Lisp_Object attack, orig_fn;
8dbbc384
RS
368 register char *lfname, *locker;
369 lock_info_type lock_info;
8489eb67 370
5383bc6d 371 orig_fn = fn;
1e89de84
KH
372 fn = Fexpand_file_name (fn, Qnil);
373
8dbbc384 374 /* Create the name of the lock-file for file fn */
7b92975f 375 MAKE_LOCK_NAME (lfname, fn);
8489eb67 376
32676c08
JB
377 /* See if this file is visited and has changed on disk since it was
378 visited. */
8489eb67 379 {
a57bc488 380 register Lisp_Object subject_buf;
5383bc6d 381 subject_buf = get_truename_buffer (orig_fn);
265a9e55
JB
382 if (!NILP (subject_buf)
383 && NILP (Fverify_visited_file_modtime (subject_buf))
384 && !NILP (Ffile_exists_p (fn)))
8489eb67
RS
385 call1 (intern ("ask-user-about-supersession-threat"), fn);
386 }
387
388 /* Try to lock the lock. */
8dbbc384
RS
389 if (lock_if_free (&lock_info, lfname) <= 0)
390 /* Return now if we have locked it, or if lock creation failed */
8489eb67
RS
391 return;
392
393 /* Else consider breaking the lock */
266d7a00
RS
394 locker = (char *) alloca (strlen (lock_info.user) + strlen (lock_info.host)
395 + LOCK_PID_MAX + 9);
79e51eeb 396 sprintf (locker, "%s@%s (pid %lu)", lock_info.user, lock_info.host,
8dbbc384
RS
397 lock_info.pid);
398 FREE_LOCK_INFO (lock_info);
399
400 attack = call2 (intern ("ask-user-about-lock"), fn, build_string (locker));
265a9e55 401 if (!NILP (attack))
8489eb67
RS
402 /* User says take the lock */
403 {
8dbbc384 404 lock_file_1 (lfname, 1);
8489eb67
RS
405 return;
406 }
407 /* User says ignore the lock */
408}
409
8489eb67
RS
410void
411unlock_file (fn)
412 register Lisp_Object fn;
413{
414 register char *lfname;
415
1e89de84
KH
416 fn = Fexpand_file_name (fn, Qnil);
417
7b92975f 418 MAKE_LOCK_NAME (lfname, fn);
8489eb67 419
8dbbc384 420 if (current_lock_owner (0, lfname) == 2)
8489eb67 421 unlink (lfname);
8489eb67
RS
422}
423
424void
425unlock_all_files ()
426{
427 register Lisp_Object tail;
428 register struct buffer *b;
429
4e6c9d9e 430 for (tail = Vbuffer_alist; GC_CONSP (tail); tail = XCONS (tail)->cdr)
8489eb67
RS
431 {
432 b = XBUFFER (XCONS (XCONS (tail)->car)->cdr);
5757b805 433 if (STRINGP (b->file_truename) && BUF_SAVE_MODIFF (b) < BUF_MODIFF (b))
1c343051
KH
434 {
435 register char *lfname;
436
437 MAKE_LOCK_NAME (lfname, b->file_truename);
438
439 if (current_lock_owner (0, lfname) == 2)
440 unlink (lfname);
441 }
8489eb67
RS
442 }
443}
8489eb67
RS
444\f
445DEFUN ("lock-buffer", Flock_buffer, Slock_buffer,
446 0, 1, 0,
447 "Lock FILE, if current buffer is modified.\n\
448FILE defaults to current buffer's visited file,\n\
449or else nothing is done if current buffer isn't visiting a file.")
e9319ef2
EN
450 (file)
451 Lisp_Object file;
8489eb67 452{
e9319ef2
EN
453 if (NILP (file))
454 file = current_buffer->file_truename;
8489eb67 455 else
e9319ef2 456 CHECK_STRING (file, 0);
6a140159 457 if (SAVE_MODIFF < MODIFF
e9319ef2
EN
458 && !NILP (file))
459 lock_file (file);
8489eb67
RS
460 return Qnil;
461}
462
463DEFUN ("unlock-buffer", Funlock_buffer, Sunlock_buffer,
464 0, 0, 0,
465 "Unlock the file visited in the current buffer,\n\
466if it should normally be locked.")
467 ()
468{
6a140159 469 if (SAVE_MODIFF < MODIFF
5757b805
RS
470 && STRINGP (current_buffer->file_truename))
471 unlock_file (current_buffer->file_truename);
8489eb67
RS
472 return Qnil;
473}
474
8489eb67
RS
475/* Unlock the file visited in buffer BUFFER. */
476
d07e0802 477void
8489eb67
RS
478unlock_buffer (buffer)
479 struct buffer *buffer;
480{
6a140159 481 if (BUF_SAVE_MODIFF (buffer) < BUF_MODIFF (buffer)
5757b805
RS
482 && STRINGP (buffer->file_truename))
483 unlock_file (buffer->file_truename);
8489eb67
RS
484}
485
486DEFUN ("file-locked-p", Ffile_locked_p, Sfile_locked_p, 0, 1, 0,
487 "Return nil if the FILENAME is not locked,\n\
488t if it is locked by you, else a string of the name of the locker.")
e9319ef2
EN
489 (filename)
490 Lisp_Object filename;
8489eb67 491{
8dbbc384 492 Lisp_Object ret;
8489eb67
RS
493 register char *lfname;
494 int owner;
8dbbc384 495 lock_info_type locker;
8489eb67 496
e9319ef2 497 filename = Fexpand_file_name (filename, Qnil);
8489eb67 498
e9319ef2 499 MAKE_LOCK_NAME (lfname, filename);
8489eb67 500
8dbbc384 501 owner = current_lock_owner (&locker, lfname);
8489eb67 502 if (owner <= 0)
8dbbc384
RS
503 ret = Qnil;
504 else if (owner == 2)
505 ret = Qt;
506 else
507 ret = build_string (locker.user);
508
509 if (owner > 0)
510 FREE_LOCK_INFO (locker);
511
512 return ret;
8489eb67 513}
32676c08
JB
514\f
515/* Initialization functions. */
516
8489eb67
RS
517syms_of_filelock ()
518{
519 defsubr (&Sunlock_buffer);
520 defsubr (&Slock_buffer);
521 defsubr (&Sfile_locked_p);
522}
523
524#endif /* CLASH_DETECTION */