*** empty log message ***
[bpt/emacs.git] / src / filelock.c
CommitLineData
32676c08 1/* Copyright (C) 1985, 1986, 1987, 1992 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
17the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
18
19
20#include <sys/types.h>
21#include <sys/stat.h>
22#include "config.h"
bfb61299
JB
23
24#ifdef VMS
b350a838 25#include "vms-pwd.h"
bfb61299 26#else
8489eb67 27#include <pwd.h>
bfb61299
JB
28#endif
29
8489eb67
RS
30#include <errno.h>
31#include <sys/file.h>
32#ifdef USG
33#include <fcntl.h>
34#endif /* USG */
35
8489eb67
RS
36#include "lisp.h"
37#include "paths.h"
38#include "buffer.h"
39
40extern int errno;
41
32676c08
JB
42extern char *egetenv ();
43
8489eb67
RS
44#ifdef CLASH_DETECTION
45
46/* If system does not have symbolic links, it does not have lstat.
47 In that case, use ordinary stat instead. */
48
49#ifndef S_IFLNK
50#define lstat stat
51#endif
52
32676c08
JB
53
54/* The name of the directory in which we keep lock files, with a '/'
55 appended. */
56char *lock_path;
57
58/* The name of the file in the lock directory which is used to
59 arbitrate access to the entire directory. */
60#define SUPERLOCK_NAME "!!!SuperLock!!!"
61
62/* The path to the superlock file. This is SUPERLOCK_NAME appended to
63 lock_path. */
64char *superlock_path;
65
66/* Set LOCK to the name of the lock file for the filename FILE.
67 char *LOCK; Lisp_Object FILE; */
68#define MAKE_LOCK_PATH (lock, file) \
69 (lock = (char *) alloca (XSTRING (file)->size + strlen (lock_path) + 1), \
70 fill_in_lock_file_name (lock, (file)))
71
72fill_in_lock_file_name (lockfile, fn)
73 register char *lockfile;
74 register Lisp_Object fn;
75{
76 register char *p;
77
78 strcpy (lockfile, lock_path);
79
80 p = lockfile + strlen (lockfile);
81
82 strcpy (p, XSTRING (fn)->data);
83
84 for (; *p; p++)
85 {
86 if (*p == '/')
87 *p = '!';
88 }
89}
90
8489eb67
RS
91static Lisp_Object
92lock_file_owner_name (lfname)
93 char *lfname;
94{
95 struct stat s;
96 struct passwd *the_pw;
97 extern struct passwd *getpwuid ();
98
99 if (lstat (lfname, &s) == 0)
100 the_pw = getpwuid (s.st_uid);
101 return (the_pw == 0 ? Qnil : build_string (the_pw->pw_name));
102}
103
104
105/* lock_file locks file fn,
106 meaning it serves notice on the world that you intend to edit that file.
107 This should be done only when about to modify a file-visiting
108 buffer previously unmodified.
109 Do not (normally) call lock_buffer for a buffer already modified,
110 as either the file is already locked, or the user has already
111 decided to go ahead without locking.
112
113 When lock_buffer returns, either the lock is locked for us,
114 or the user has said to go ahead without locking.
115
116 If the file is locked by someone else, lock_buffer calls
117 ask-user-about-lock (a Lisp function) with two arguments,
118 the file name and the name of the user who did the locking.
119 This function can signal an error, or return t meaning
120 take away the lock, or return nil meaning ignore the lock. */
121
122/* The lock file name is the file name with "/" replaced by "!"
123 and put in the Emacs lock directory. */
124/* (ie., /ka/king/junk.tex -> /!/!ka!king!junk.tex). */
125
126void
127lock_file (fn)
128 register Lisp_Object fn;
129{
130 register Lisp_Object attack;
131 register char *lfname;
132
32676c08 133 MAKE_LOCK_PATH (lfname, fn);
8489eb67 134
32676c08
JB
135 /* See if this file is visited and has changed on disk since it was
136 visited. */
8489eb67
RS
137 {
138 register Lisp_Object subject_buf = Fget_file_buffer (fn);
265a9e55
JB
139 if (!NILP (subject_buf)
140 && NILP (Fverify_visited_file_modtime (subject_buf))
141 && !NILP (Ffile_exists_p (fn)))
8489eb67
RS
142 call1 (intern ("ask-user-about-supersession-threat"), fn);
143 }
144
145 /* Try to lock the lock. */
146 if (lock_if_free (lfname) <= 0)
147 /* Return now if we have locked it, or if lock dir does not exist */
148 return;
149
150 /* Else consider breaking the lock */
151 attack = call2 (intern ("ask-user-about-lock"), fn,
152 lock_file_owner_name (lfname));
265a9e55 153 if (!NILP (attack))
8489eb67
RS
154 /* User says take the lock */
155 {
156 lock_superlock (lfname);
157 lock_file_1 (lfname, O_WRONLY) ;
32676c08 158 unlink (superlock_path);
8489eb67
RS
159 return;
160 }
161 /* User says ignore the lock */
162}
163
8489eb67
RS
164/* Lock the lock file named LFNAME.
165 If MODE is O_WRONLY, we do so even if it is already locked.
166 If MODE is O_WRONLY | O_EXCL | O_CREAT, we do so only if it is free.
167 Return 1 if successful, 0 if not. */
168
169int
170lock_file_1 (lfname, mode)
171 int mode; char *lfname;
172{
173 register int fd;
174 char buf[20];
175
176 if ((fd = open (lfname, mode, 0666)) >= 0)
177 {
178#ifdef USG
179 chmod (lfname, 0666);
180#else
181 fchmod (fd, 0666);
182#endif
183 sprintf (buf, "%d ", getpid ());
184 write (fd, buf, strlen (buf));
185 close (fd);
186 return 1;
187 }
188 else
189 return 0;
190}
191
192/* Lock the lock named LFNAME if possible.
193 Return 0 in that case.
194 Return positive if lock is really locked by someone else.
195 Return -1 if cannot lock for any other reason. */
196
197int
198lock_if_free (lfname)
199 register char *lfname;
200{
201 register int clasher;
202
203 while (lock_file_1 (lfname, O_WRONLY | O_EXCL | O_CREAT) == 0)
204 {
205 if (errno != EEXIST)
206 return -1;
207 clasher = current_lock_owner (lfname);
208 if (clasher != 0)
209 if (clasher != getpid ())
210 return (clasher);
211 else return (0);
212 /* Try again to lock it */
213 }
214 return 0;
215}
216
217/* Return the pid of the process that claims to own the lock file LFNAME,
218 or 0 if nobody does or the lock is obsolete,
219 or -1 if something is wrong with the locking mechanism. */
220
221int
222current_lock_owner (lfname)
223 char *lfname;
224{
225 int owner = current_lock_owner_1 (lfname);
226 if (owner == 0 && errno == ENOENT)
227 return (0);
228 /* Is it locked by a process that exists? */
229 if (owner != 0 && (kill (owner, 0) >= 0 || errno == EPERM))
230 return (owner);
231 if (unlink (lfname) < 0)
232 return (-1);
233 return (0);
234}
235
236int
237current_lock_owner_1 (lfname)
238 char *lfname;
239{
240 register int fd;
241 char buf[20];
242 int tem;
243
244 fd = open (lfname, O_RDONLY, 0666);
245 if (fd < 0)
246 return 0;
247 tem = read (fd, buf, sizeof buf);
248 close (fd);
249 return (tem <= 0 ? 0 : atoi (buf));
250}
251
252\f
253void
254unlock_file (fn)
255 register Lisp_Object fn;
256{
257 register char *lfname;
258
32676c08 259 MAKE_LOCK_PATH (lfname, fn);
8489eb67
RS
260
261 lock_superlock (lfname);
262
263 if (current_lock_owner_1 (lfname) == getpid ())
264 unlink (lfname);
265
32676c08 266 unlink (superlock_path);
8489eb67
RS
267}
268
269lock_superlock (lfname)
270 char *lfname;
271{
272 register int i, fd;
273
32676c08 274 for (i = -20; i < 0 && (fd = open (superlock_path,
8489eb67
RS
275 O_WRONLY | O_EXCL | O_CREAT, 0666)) < 0;
276 i++)
277 {
278 if (errno != EEXIST)
279 return;
280 sleep (1);
281 }
282 if (fd >= 0)
283 {
284#ifdef USG
32676c08 285 chmod (superlock_path, 0666);
8489eb67
RS
286#else
287 fchmod (fd, 0666);
288#endif
289 write (fd, lfname, strlen (lfname));
290 close (fd);
291 }
292}
293
294void
295unlock_all_files ()
296{
297 register Lisp_Object tail;
298 register struct buffer *b;
299
300 for (tail = Vbuffer_alist; XGCTYPE (tail) == Lisp_Cons;
301 tail = XCONS (tail)->cdr)
302 {
303 b = XBUFFER (XCONS (XCONS (tail)->car)->cdr);
304 if (XTYPE (b->filename) == Lisp_String &&
305 b->save_modified < BUF_MODIFF (b))
306 unlock_file (b->filename);
307 }
308}
309
310\f
311DEFUN ("lock-buffer", Flock_buffer, Slock_buffer,
312 0, 1, 0,
313 "Lock FILE, if current buffer is modified.\n\
314FILE defaults to current buffer's visited file,\n\
315or else nothing is done if current buffer isn't visiting a file.")
316 (fn)
317 Lisp_Object fn;
318{
265a9e55 319 if (NILP (fn))
8489eb67
RS
320 fn = current_buffer->filename;
321 else
322 CHECK_STRING (fn, 0);
323 if (current_buffer->save_modified < MODIFF
265a9e55 324 && !NILP (fn))
8489eb67
RS
325 lock_file (fn);
326 return Qnil;
327}
328
329DEFUN ("unlock-buffer", Funlock_buffer, Sunlock_buffer,
330 0, 0, 0,
331 "Unlock the file visited in the current buffer,\n\
332if it should normally be locked.")
333 ()
334{
335 if (current_buffer->save_modified < MODIFF &&
336 XTYPE (current_buffer->filename) == Lisp_String)
337 unlock_file (current_buffer->filename);
338 return Qnil;
339}
340
341\f
342/* Unlock the file visited in buffer BUFFER. */
343
344unlock_buffer (buffer)
345 struct buffer *buffer;
346{
347 if (buffer->save_modified < BUF_MODIFF (buffer) &&
348 XTYPE (buffer->filename) == Lisp_String)
349 unlock_file (buffer->filename);
350}
351
352DEFUN ("file-locked-p", Ffile_locked_p, Sfile_locked_p, 0, 1, 0,
353 "Return nil if the FILENAME is not locked,\n\
354t if it is locked by you, else a string of the name of the locker.")
355 (fn)
356 Lisp_Object fn;
357{
358 register char *lfname;
359 int owner;
360
361 fn = Fexpand_file_name (fn, Qnil);
362
32676c08 363 MAKE_LOCK_PATH (lfname, fn);
8489eb67
RS
364
365 owner = current_lock_owner (lfname);
366 if (owner <= 0)
367 return (Qnil);
368 else if (owner == getpid ())
369 return (Qt);
370
371 return (lock_file_owner_name (lfname));
372}
373
32676c08
JB
374\f
375/* Initialization functions. */
376
377init_filelock ()
378{
379 lock_path = egetenv ("EMACSLOCKDIR");
380 if (! lock_path)
381 lock_path = PATH_LOCK;
382
383 /* Make sure it ends with a slash. */
384 if (lock_path[strlen (lock_path) - 1] != '/')
385 {
386 lock_path = strcpy ((char *) xmalloc (strlen (lock_path) + 2),
387 lock_path);
388 strcat (lock_path, "/");
389 }
390
391 superlock_path = (char *) xmalloc ((strlen (lock_path)
392 + sizeof (SUPERLOCK_NAME)));
393 strcpy (superlock_path, lock_path);
394 strcat (superlock_path, SUPERLOCK_NAME);
395}
396
8489eb67
RS
397syms_of_filelock ()
398{
399 defsubr (&Sunlock_buffer);
400 defsubr (&Slock_buffer);
401 defsubr (&Sfile_locked_p);
402}
403
404#endif /* CLASH_DETECTION */