]> code.delx.au - gnu-emacs/blob - src/filelock.c
(load_face_colors): Load background color if setting
[gnu-emacs] / src / filelock.c
1 /* Lock files for editing.
2 Copyright (C) 1985, 86, 87, 93, 94, 96, 98, 1999 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20
21
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <signal.h>
25 #include <config.h>
26
27 #ifdef VMS
28 #include "vms-pwd.h"
29 #else
30 #include <pwd.h>
31 #endif /* not VMS */
32
33 #include <sys/file.h>
34 #ifdef USG
35 #include <fcntl.h>
36 #include <string.h>
37 #endif /* USG */
38
39 #ifdef HAVE_UNISTD_H
40 #include <unistd.h>
41 #endif
42
43 #ifdef __FreeBSD__
44 #include <sys/time.h>
45 #include <sys/types.h>
46 #include <sys/sysctl.h>
47 #endif /* __FreeBSD__ */
48
49 #include "lisp.h"
50 #include "buffer.h"
51 #include "charset.h"
52 #include "coding.h"
53 #include "systime.h"
54
55 #include <time.h>
56 #include <errno.h>
57 #ifndef errno
58 extern int errno;
59 #endif
60
61 #ifdef CLASH_DETECTION
62
63 #include <utmp.h>
64
65 /* A file whose last-modified time is just after the most recent boot.
66 Define this to be NULL to disable checking for this file. */
67 #ifndef BOOT_TIME_FILE
68 #define BOOT_TIME_FILE "/var/run/random-seed"
69 #endif
70
71 #ifndef WTMP_FILE
72 #define WTMP_FILE "/var/log/wtmp"
73 #endif
74
75 /* The strategy: to lock a file FN, create a symlink .#FN in FN's
76 directory, with link data `user@host.pid'. This avoids a single
77 mount (== failure) point for lock files.
78
79 When the host in the lock data is the current host, we can check if
80 the pid is valid with kill.
81
82 Otherwise, we could look at a separate file that maps hostnames to
83 reboot times to see if the remote pid can possibly be valid, since we
84 don't want Emacs to have to communicate via pipes or sockets or
85 whatever to other processes, either locally or remotely; rms says
86 that's too unreliable. Hence the separate file, which could
87 theoretically be updated by daemons running separately -- but this
88 whole idea is unimplemented; in practice, at least in our
89 environment, it seems such stale locks arise fairly infrequently, and
90 Emacs' standard methods of dealing with clashes suffice.
91
92 We use symlinks instead of normal files because (1) they can be
93 stored more efficiently on the filesystem, since the kernel knows
94 they will be small, and (2) all the info about the lock can be read
95 in a single system call (readlink). Although we could use regular
96 files to be useful on old systems lacking symlinks, nowadays
97 virtually all such systems are probably single-user anyway, so it
98 didn't seem worth the complication.
99
100 Similarly, we don't worry about a possible 14-character limit on
101 file names, because those are all the same systems that don't have
102 symlinks.
103
104 This is compatible with the locking scheme used by Interleaf (which
105 has contributed this implementation for Emacs), and was designed by
106 Ethan Jacobson, Kimbo Mundy, and others.
107
108 --karl@cs.umb.edu/karl@hq.ileaf.com. */
109
110 \f
111 /* Return the time of the last system boot. */
112
113 static time_t boot_time;
114 static int boot_time_initialized;
115
116 extern Lisp_Object Vshell_file_name;
117
118 static time_t
119 get_boot_time ()
120 {
121 int counter;
122
123 if (boot_time_initialized)
124 return boot_time;
125 boot_time_initialized = 1;
126
127 #if defined (CTL_KERN) && defined (KERN_BOOTTIME)
128 {
129 int mib[2];
130 size_t size;
131 struct timeval boottime_val;
132
133 mib[0] = CTL_KERN;
134 mib[1] = KERN_BOOTTIME;
135 size = sizeof (boottime_val);
136
137 if (sysctl (mib, 2, &boottime_val, &size, NULL, 0) >= 0)
138 {
139 boot_time = boottime_val.tv_sec;
140 return boot_time;
141 }
142 }
143 #endif /* defined (CTL_KERN) && defined (KERN_BOOTTIME) */
144
145 if (BOOT_TIME_FILE)
146 {
147 struct stat st;
148 if (stat (BOOT_TIME_FILE, &st) == 0)
149 {
150 boot_time = st.st_mtime;
151 return boot_time;
152 }
153 }
154
155 #if defined (BOOT_TIME) && ! defined (NO_WTMP_FILE)
156 #ifndef CANNOT_DUMP
157 /* The utmp routines maintain static state.
158 Don't touch that state unless we are initialized,
159 since it might not survive dumping. */
160 if (! initialized)
161 return boot_time;
162 #endif /* not CANNOT_DUMP */
163
164 /* Try to get boot time from utmp before wtmp,
165 since utmp is typically much smaller than wtmp.
166 Passing a null pointer causes get_boot_time_1
167 to inspect the default file, namely utmp. */
168 get_boot_time_1 ((char *) 0, 0);
169 if (boot_time)
170 return boot_time;
171
172 /* Try to get boot time from the current wtmp file. */
173 get_boot_time_1 (WTMP_FILE, 1);
174
175 /* If we did not find a boot time in wtmp, look at wtmp, and so on. */
176 for (counter = 0; counter < 20 && ! boot_time; counter++)
177 {
178 char cmd_string[100];
179 Lisp_Object tempname, filename;
180 int delete_flag = 0;
181
182 filename = Qnil;
183
184 sprintf (cmd_string, "%s.%d", WTMP_FILE, counter);
185 tempname = build_string (cmd_string);
186 if (! NILP (Ffile_exists_p (tempname)))
187 filename = tempname;
188 else
189 {
190 sprintf (cmd_string, "%s.%d.gz", WTMP_FILE, counter);
191 tempname = build_string (cmd_string);
192 if (! NILP (Ffile_exists_p (tempname)))
193 {
194 Lisp_Object args[6];
195 tempname = Fmake_temp_name (build_string ("wtmp"));
196 args[0] = Vshell_file_name;
197 args[1] = Qnil;
198 args[2] = Qnil;
199 args[3] = Qnil;
200 args[4] = build_string ("-c");
201 sprintf (cmd_string, "gunzip < %s.%d.gz > %s",
202 WTMP_FILE, counter, XSTRING (tempname)->data);
203 args[5] = build_string (cmd_string);
204 Fcall_process (6, args);
205 filename = tempname;
206 delete_flag = 1;
207 }
208 }
209
210 if (! NILP (filename))
211 {
212 get_boot_time_1 (XSTRING (filename)->data, 1);
213 if (delete_flag)
214 unlink (XSTRING (filename)->data);
215 }
216 }
217
218 return boot_time;
219 #else
220 return 0;
221 #endif
222 }
223
224 #ifdef BOOT_TIME
225 /* Try to get the boot time from wtmp file FILENAME.
226 This succeeds if that file contains a reboot record.
227
228 If FILENAME is zero, use the same file as before;
229 if no FILENAME has ever been specified, this is the utmp file.
230 Use the newest reboot record if NEWEST is nonzero,
231 the first reboot record otherwise.
232 Ignore all reboot records on or before BOOT_TIME.
233 Success is indicated by setting BOOT_TIME to a larger value. */
234
235 get_boot_time_1 (filename, newest)
236 char *filename;
237 int newest;
238 {
239 struct utmp ut, *utp;
240 int desc;
241
242 if (filename)
243 {
244 /* On some versions of IRIX, opening a nonexistent file name
245 is likely to crash in the utmp routines. */
246 desc = open (filename, O_RDONLY);
247 if (desc < 0)
248 return;
249
250 close (desc);
251
252 utmpname (filename);
253 }
254
255 setutent ();
256
257 while (1)
258 {
259 /* Find the next reboot record. */
260 ut.ut_type = BOOT_TIME;
261 utp = getutid (&ut);
262 if (! utp)
263 break;
264 /* Compare reboot times and use the newest one. */
265 if (utp->ut_time > boot_time)
266 {
267 boot_time = utp->ut_time;
268 if (! newest)
269 break;
270 }
271 /* Advance on element in the file
272 so that getutid won't repeat the same one. */
273 utp = getutent ();
274 if (! utp)
275 break;
276 }
277 endutent ();
278 }
279 #endif /* BOOT_TIME */
280 \f
281 /* Here is the structure that stores information about a lock. */
282
283 typedef struct
284 {
285 char *user;
286 char *host;
287 unsigned long pid;
288 time_t boot_time;
289 } lock_info_type;
290
291 /* When we read the info back, we might need this much more,
292 enough for decimal representation plus null. */
293 #define LOCK_PID_MAX (4 * sizeof (unsigned long))
294
295 /* Free the two dynamically-allocated pieces in PTR. */
296 #define FREE_LOCK_INFO(i) do { xfree ((i).user); xfree ((i).host); } while (0)
297
298
299 /* Write the name of the lock file for FN into LFNAME. Length will be
300 that of FN plus two more for the leading `.#' plus one for the null. */
301 #define MAKE_LOCK_NAME(lock, file) \
302 (lock = (char *) alloca (STRING_BYTES (XSTRING (file)) + 2 + 1), \
303 fill_in_lock_file_name (lock, (file)))
304
305 static void
306 fill_in_lock_file_name (lockfile, fn)
307 register char *lockfile;
308 register Lisp_Object fn;
309 {
310 register char *p;
311
312 strcpy (lockfile, XSTRING (fn)->data);
313
314 /* Shift the nondirectory part of the file name (including the null)
315 right two characters. Here is one of the places where we'd have to
316 do something to support 14-character-max file names. */
317 for (p = lockfile + strlen (lockfile); p != lockfile && *p != '/'; p--)
318 p[2] = *p;
319
320 /* Insert the `.#'. */
321 p[1] = '.';
322 p[2] = '#';
323 }
324
325 /* Lock the lock file named LFNAME.
326 If FORCE is nonzero, we do so even if it is already locked.
327 Return 1 if successful, 0 if not. */
328
329 static int
330 lock_file_1 (lfname, force)
331 char *lfname;
332 int force;
333 {
334 register int err;
335 time_t boot_time;
336 char *user_name;
337 char *host_name;
338 char *lock_info_str;
339
340 if (STRINGP (Fuser_login_name (Qnil)))
341 user_name = (char *)XSTRING (Fuser_login_name (Qnil))->data;
342 else
343 user_name = "";
344 if (STRINGP (Fsystem_name ()))
345 host_name = (char *)XSTRING (Fsystem_name ())->data;
346 else
347 host_name = "";
348 lock_info_str = (char *)alloca (strlen (user_name) + strlen (host_name)
349 + LOCK_PID_MAX + 5);
350
351 boot_time = get_boot_time ();
352 if (boot_time)
353 sprintf (lock_info_str, "%s@%s.%lu:%lu", user_name, host_name,
354 (unsigned long) getpid (), (unsigned long) boot_time);
355 else
356 sprintf (lock_info_str, "%s@%s.%lu", user_name, host_name,
357 (unsigned long) getpid ());
358
359 err = symlink (lock_info_str, lfname);
360 if (errno == EEXIST && force)
361 {
362 unlink (lfname);
363 err = symlink (lock_info_str, lfname);
364 }
365
366 return err == 0;
367 }
368
369 /* Return 1 if times A and B are no more than one second apart. */
370
371 int
372 within_one_second (a, b)
373 time_t a, b;
374 {
375 return (a - b >= -1 && a - b <= 1);
376 }
377 \f
378 /* Return 0 if nobody owns the lock file LFNAME or the lock is obsolete,
379 1 if another process owns it (and set OWNER (if non-null) to info),
380 2 if the current process owns it,
381 or -1 if something is wrong with the locking mechanism. */
382
383 static int
384 current_lock_owner (owner, lfname)
385 lock_info_type *owner;
386 char *lfname;
387 {
388 #ifndef index
389 extern char *rindex (), *index ();
390 #endif
391 int o, p, len, ret;
392 int local_owner = 0;
393 char *at, *dot, *colon;
394 char *lfinfo = 0;
395 int bufsize = 50;
396 /* Read arbitrarily-long contents of symlink. Similar code in
397 file-symlink-p in fileio.c. */
398 do
399 {
400 bufsize *= 2;
401 lfinfo = (char *) xrealloc (lfinfo, bufsize);
402 len = readlink (lfname, lfinfo, bufsize);
403 }
404 while (len >= bufsize);
405
406 /* If nonexistent lock file, all is well; otherwise, got strange error. */
407 if (len == -1)
408 {
409 xfree (lfinfo);
410 return errno == ENOENT ? 0 : -1;
411 }
412
413 /* Link info exists, so `len' is its length. Null terminate. */
414 lfinfo[len] = 0;
415
416 /* Even if the caller doesn't want the owner info, we still have to
417 read it to determine return value, so allocate it. */
418 if (!owner)
419 {
420 owner = (lock_info_type *) alloca (sizeof (lock_info_type));
421 local_owner = 1;
422 }
423
424 /* Parse USER@HOST.PID:BOOT_TIME. If can't parse, return -1. */
425 /* The USER is everything before the first @. */
426 at = index (lfinfo, '@');
427 dot = rindex (lfinfo, '.');
428 if (!at || !dot)
429 {
430 xfree (lfinfo);
431 return -1;
432 }
433 len = at - lfinfo;
434 owner->user = (char *) xmalloc (len + 1);
435 strncpy (owner->user, lfinfo, len);
436 owner->user[len] = 0;
437
438 /* The PID is everything from the last `.' to the `:'. */
439 owner->pid = atoi (dot + 1);
440 colon = dot;
441 while (*colon && *colon != ':')
442 colon++;
443 /* After the `:', if there is one, comes the boot time. */
444 if (*colon == ':')
445 owner->boot_time = atoi (colon + 1);
446 else
447 owner->boot_time = 0;
448
449 /* The host is everything in between. */
450 len = dot - at - 1;
451 owner->host = (char *) xmalloc (len + 1);
452 strncpy (owner->host, at + 1, len);
453 owner->host[len] = 0;
454
455 /* We're done looking at the link info. */
456 xfree (lfinfo);
457
458 /* On current host? */
459 if (STRINGP (Fsystem_name ())
460 && strcmp (owner->host, XSTRING (Fsystem_name ())->data) == 0)
461 {
462 if (owner->pid == getpid ())
463 ret = 2; /* We own it. */
464 else if (owner->pid > 0
465 && (kill (owner->pid, 0) >= 0 || errno == EPERM)
466 && (owner->boot_time == 0
467 || within_one_second (owner->boot_time, get_boot_time ())))
468 ret = 1; /* An existing process on this machine owns it. */
469 /* The owner process is dead or has a strange pid (<=0), so try to
470 zap the lockfile. */
471 else if (unlink (lfname) < 0)
472 ret = -1;
473 else
474 ret = 0;
475 }
476 else
477 { /* If we wanted to support the check for stale locks on remote machines,
478 here's where we'd do it. */
479 ret = 1;
480 }
481
482 /* Avoid garbage. */
483 if (local_owner || ret <= 0)
484 {
485 FREE_LOCK_INFO (*owner);
486 }
487 return ret;
488 }
489
490 \f
491 /* Lock the lock named LFNAME if possible.
492 Return 0 in that case.
493 Return positive if some other process owns the lock, and info about
494 that process in CLASHER.
495 Return -1 if cannot lock for any other reason. */
496
497 static int
498 lock_if_free (clasher, lfname)
499 lock_info_type *clasher;
500 register char *lfname;
501 {
502 while (lock_file_1 (lfname, 0) == 0)
503 {
504 int locker;
505
506 if (errno != EEXIST)
507 return -1;
508
509 locker = current_lock_owner (clasher, lfname);
510 if (locker == 2)
511 {
512 FREE_LOCK_INFO (*clasher);
513 return 0; /* We ourselves locked it. */
514 }
515 else if (locker == 1)
516 return 1; /* Someone else has it. */
517 else if (locker == -1)
518 return -1; /* current_lock_owner() returned strange error */
519
520 /* We deleted a stale lock; try again to lock the file. */
521 }
522 return 0;
523 }
524
525 /* lock_file locks file FN,
526 meaning it serves notice on the world that you intend to edit that file.
527 This should be done only when about to modify a file-visiting
528 buffer previously unmodified.
529 Do not (normally) call this for a buffer already modified,
530 as either the file is already locked, or the user has already
531 decided to go ahead without locking.
532
533 When this returns, either the lock is locked for us,
534 or the user has said to go ahead without locking.
535
536 If the file is locked by someone else, this calls
537 ask-user-about-lock (a Lisp function) with two arguments,
538 the file name and info about the user who did the locking.
539 This function can signal an error, or return t meaning
540 take away the lock, or return nil meaning ignore the lock. */
541
542 void
543 lock_file (fn)
544 Lisp_Object fn;
545 {
546 register Lisp_Object attack, orig_fn, encoded_fn;
547 register char *lfname, *locker;
548 lock_info_type lock_info;
549
550 /* Don't do locking while dumping Emacs.
551 Uncompressing wtmp files uses call-process, which does not work
552 in an uninitialized Emacs. */
553 if (! NILP (Vpurify_flag))
554 return;
555
556 orig_fn = fn;
557 fn = Fexpand_file_name (fn, Qnil);
558 encoded_fn = ENCODE_FILE (fn);
559
560 /* Create the name of the lock-file for file fn */
561 MAKE_LOCK_NAME (lfname, encoded_fn);
562
563 /* See if this file is visited and has changed on disk since it was
564 visited. */
565 {
566 register Lisp_Object subject_buf;
567 struct gcpro gcpro1;
568
569 subject_buf = get_truename_buffer (orig_fn);
570 GCPRO1 (fn);
571
572 if (!NILP (subject_buf)
573 && NILP (Fverify_visited_file_modtime (subject_buf))
574 && !NILP (Ffile_exists_p (fn)))
575 call1 (intern ("ask-user-about-supersession-threat"), fn);
576
577 UNGCPRO;
578 }
579
580 /* Try to lock the lock. */
581 if (lock_if_free (&lock_info, lfname) <= 0)
582 /* Return now if we have locked it, or if lock creation failed */
583 return;
584
585 /* Else consider breaking the lock */
586 locker = (char *) alloca (strlen (lock_info.user) + strlen (lock_info.host)
587 + LOCK_PID_MAX + 9);
588 sprintf (locker, "%s@%s (pid %lu)", lock_info.user, lock_info.host,
589 lock_info.pid);
590 FREE_LOCK_INFO (lock_info);
591
592 attack = call2 (intern ("ask-user-about-lock"), fn, build_string (locker));
593 if (!NILP (attack))
594 /* User says take the lock */
595 {
596 lock_file_1 (lfname, 1);
597 return;
598 }
599 /* User says ignore the lock */
600 }
601
602 void
603 unlock_file (fn)
604 register Lisp_Object fn;
605 {
606 register char *lfname;
607
608 fn = Fexpand_file_name (fn, Qnil);
609 fn = ENCODE_FILE (fn);
610
611 MAKE_LOCK_NAME (lfname, fn);
612
613 if (current_lock_owner (0, lfname) == 2)
614 unlink (lfname);
615 }
616
617 void
618 unlock_all_files ()
619 {
620 register Lisp_Object tail;
621 register struct buffer *b;
622
623 for (tail = Vbuffer_alist; GC_CONSP (tail); tail = XCONS (tail)->cdr)
624 {
625 b = XBUFFER (XCONS (XCONS (tail)->car)->cdr);
626 if (STRINGP (b->file_truename) && BUF_SAVE_MODIFF (b) < BUF_MODIFF (b))
627 {
628 register char *lfname;
629
630 MAKE_LOCK_NAME (lfname, b->file_truename);
631
632 if (current_lock_owner (0, lfname) == 2)
633 unlink (lfname);
634 }
635 }
636 }
637 \f
638 DEFUN ("lock-buffer", Flock_buffer, Slock_buffer,
639 0, 1, 0,
640 "Lock FILE, if current buffer is modified.\n\
641 FILE defaults to current buffer's visited file,\n\
642 or else nothing is done if current buffer isn't visiting a file.")
643 (file)
644 Lisp_Object file;
645 {
646 if (NILP (file))
647 file = current_buffer->file_truename;
648 else
649 CHECK_STRING (file, 0);
650 if (SAVE_MODIFF < MODIFF
651 && !NILP (file))
652 lock_file (file);
653 return Qnil;
654 }
655
656 DEFUN ("unlock-buffer", Funlock_buffer, Sunlock_buffer,
657 0, 0, 0,
658 "Unlock the file visited in the current buffer,\n\
659 if it should normally be locked.")
660 ()
661 {
662 if (SAVE_MODIFF < MODIFF
663 && STRINGP (current_buffer->file_truename))
664 unlock_file (current_buffer->file_truename);
665 return Qnil;
666 }
667
668 /* Unlock the file visited in buffer BUFFER. */
669
670 void
671 unlock_buffer (buffer)
672 struct buffer *buffer;
673 {
674 if (BUF_SAVE_MODIFF (buffer) < BUF_MODIFF (buffer)
675 && STRINGP (buffer->file_truename))
676 unlock_file (buffer->file_truename);
677 }
678
679 DEFUN ("file-locked-p", Ffile_locked_p, Sfile_locked_p, 0, 1, 0,
680 "Return nil if the FILENAME is not locked,\n\
681 t if it is locked by you, else a string of the name of the locker.")
682 (filename)
683 Lisp_Object filename;
684 {
685 Lisp_Object ret;
686 register char *lfname;
687 int owner;
688 lock_info_type locker;
689
690 filename = Fexpand_file_name (filename, Qnil);
691
692 MAKE_LOCK_NAME (lfname, filename);
693
694 owner = current_lock_owner (&locker, lfname);
695 if (owner <= 0)
696 ret = Qnil;
697 else if (owner == 2)
698 ret = Qt;
699 else
700 ret = build_string (locker.user);
701
702 if (owner > 0)
703 FREE_LOCK_INFO (locker);
704
705 return ret;
706 }
707 \f
708 /* Initialization functions. */
709
710 void
711 init_filelock ()
712 {
713 boot_time = 0;
714 boot_time_initialized = 0;
715 }
716
717 void
718 syms_of_filelock ()
719 {
720 defsubr (&Sunlock_buffer);
721 defsubr (&Slock_buffer);
722 defsubr (&Sfile_locked_p);
723 }
724
725 #endif /* CLASH_DETECTION */