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