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