This source file includes following definitions.
- get_boot_time
- get_boot_time_1
- rename_lock_file
- create_lock_file
- lock_file_1
- within_one_second
- read_lock_data
- current_lock_owner
- lock_if_free
- make_lock_file_name
- lock_file
- unlock_file
- unlock_file_handle_error
- unlock_all_files
- DEFUN
- DEFUN
- DEFUN
- DEFUN
- unlock_buffer
- DEFUN
- syms_of_filelock
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 #include <config.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <signal.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31
32 #ifdef HAVE_PWD_H
33 #include <pwd.h>
34 #endif
35
36 #include <sys/file.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39
40 #ifdef __FreeBSD__
41 #include <sys/sysctl.h>
42 #endif
43
44 #include <errno.h>
45
46 #include <c-ctype.h>
47
48 #include "lisp.h"
49 #include "buffer.h"
50 #include "coding.h"
51 #ifdef WINDOWSNT
52 #include <share.h>
53 #include <sys/socket.h>
54 #endif
55
56 #ifndef MSDOS
57
58 #ifdef HAVE_UTMP_H
59 #include <utmp.h>
60 #endif
61
62
63
64 #ifndef BOOT_TIME_FILE
65 #define BOOT_TIME_FILE "/var/run/random-seed"
66 #endif
67
68 #if !defined WTMP_FILE && !defined WINDOWSNT && defined BOOT_TIME
69 #define WTMP_FILE "/var/log/wtmp"
70 #endif
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126 static time_t boot_time;
127 static bool boot_time_initialized;
128
129 #ifdef BOOT_TIME
130 static void get_boot_time_1 (const char *, bool);
131 #endif
132
133 static time_t
134 get_boot_time (void)
135 {
136 #if defined (BOOT_TIME)
137 int counter;
138 #endif
139
140 if (boot_time_initialized)
141 return boot_time;
142 boot_time_initialized = 1;
143
144 #if defined (CTL_KERN) && defined (KERN_BOOTTIME)
145 {
146 int mib[2];
147 size_t size;
148 struct timeval boottime_val;
149
150 mib[0] = CTL_KERN;
151 mib[1] = KERN_BOOTTIME;
152 size = sizeof (boottime_val);
153
154 if (sysctl (mib, 2, &boottime_val, &size, NULL, 0) >= 0 && size != 0)
155 {
156 boot_time = boottime_val.tv_sec;
157 return boot_time;
158 }
159 }
160 #endif
161
162 if (BOOT_TIME_FILE)
163 {
164 struct stat st;
165 if (stat (BOOT_TIME_FILE, &st) == 0)
166 {
167 boot_time = st.st_mtime;
168 return boot_time;
169 }
170 }
171
172 #if defined (BOOT_TIME)
173
174
175 if (will_dump_p ())
176 return boot_time;
177
178
179
180
181
182 get_boot_time_1 (0, 0);
183 if (boot_time)
184 return boot_time;
185
186
187 get_boot_time_1 (WTMP_FILE, 1);
188
189
190 for (counter = 0; counter < 20 && ! boot_time; counter++)
191 {
192 Lisp_Object filename = Qnil;
193 bool delete_flag = false;
194 char cmd_string[sizeof WTMP_FILE ".19.gz"];
195 AUTO_STRING_WITH_LEN (tempname, cmd_string,
196 sprintf (cmd_string, "%s.%d", WTMP_FILE, counter));
197 if (! NILP (Ffile_exists_p (tempname)))
198 filename = tempname;
199 else
200 {
201 tempname = make_formatted_string (cmd_string, "%s.%d.gz",
202 WTMP_FILE, counter);
203 if (! NILP (Ffile_exists_p (tempname)))
204 {
205
206
207
208 filename = Fmake_temp_file_internal (build_string ("wt"), Qnil,
209 empty_unibyte_string, Qnil);
210 CALLN (Fcall_process, build_string ("gzip"), Qnil,
211 list2 (QCfile, filename), Qnil,
212 build_string ("-cd"), tempname);
213 delete_flag = true;
214 }
215 }
216
217 if (! NILP (filename))
218 {
219 get_boot_time_1 (SSDATA (filename), 1);
220 if (delete_flag)
221 unlink (SSDATA (filename));
222 }
223 }
224
225 return boot_time;
226 #else
227 return 0;
228 #endif
229 }
230
231 #ifdef BOOT_TIME
232
233
234
235
236
237
238
239
240
241
242 void
243 get_boot_time_1 (const char *filename, bool newest)
244 {
245 struct utmp ut, *utp;
246
247 if (filename)
248 utmpname (filename);
249
250 setutent ();
251
252 while (1)
253 {
254
255 ut.ut_type = BOOT_TIME;
256 utp = getutid (&ut);
257 if (! utp)
258 break;
259
260 if (utp->ut_time > boot_time)
261 {
262 boot_time = utp->ut_time;
263 if (! newest)
264 break;
265 }
266
267
268 utp = getutent ();
269 if (! utp)
270 break;
271 }
272 endutent ();
273 }
274 #endif
275
276
277
278 enum { MAX_LFINFO = 8 * 1024 };
279
280
281
282 typedef struct
283 {
284
285
286 char *at, *dot, *colon;
287
288
289
290
291
292
293 char user[MAX_LFINFO + 1 + sizeof " (pid )" - sizeof "."];
294 } lock_info_type;
295
296
297
298
299
300
301 enum { LINKS_MIGHT_NOT_WORK = EPERM };
302
303
304
305
306 static int
307 rename_lock_file (char const *old, char const *new, bool force)
308 {
309 #ifdef WINDOWSNT
310 return sys_rename_replace (old, new, force);
311 #else
312 if (! force)
313 {
314 struct stat st;
315
316 int r = renameat_noreplace (AT_FDCWD, old, AT_FDCWD, new);
317 if (! (r < 0 && errno == ENOSYS))
318 return r;
319 if (link (old, new) == 0)
320 return unlink (old) == 0 || errno == ENOENT ? 0 : -1;
321 if (errno != ENOSYS && errno != LINKS_MIGHT_NOT_WORK)
322 return -1;
323
324
325
326
327
328
329
330 if (emacs_fstatat (AT_FDCWD, new, &st, AT_SYMLINK_NOFOLLOW) == 0
331 || errno == EOVERFLOW)
332 {
333 errno = EEXIST;
334 return -1;
335 }
336 if (errno != ENOENT)
337 return -1;
338 }
339
340 return rename (old, new);
341 #endif
342 }
343
344
345
346
347
348 static int
349 create_lock_file (char *lfname, char *lock_info_str, bool force)
350 {
351 #ifdef WINDOWSNT
352
353
354
355
356 int err = ENOSYS;
357 #else
358 int err = symlink (lock_info_str, lfname) == 0 ? 0 : errno;
359 #endif
360
361 if (err == EEXIST && force)
362 {
363 unlink (lfname);
364 err = symlink (lock_info_str, lfname) == 0 ? 0 : errno;
365 }
366
367 if (err == ENOSYS || err == LINKS_MIGHT_NOT_WORK || err == ENAMETOOLONG)
368 {
369 static char const nonce_base[] = ".#-emacsXXXXXX";
370 char *last_slash = strrchr (lfname, '/');
371 ptrdiff_t lfdirlen = last_slash + 1 - lfname;
372 USE_SAFE_ALLOCA;
373 char *nonce = SAFE_ALLOCA (lfdirlen + sizeof nonce_base);
374 int fd;
375 memcpy (nonce, lfname, lfdirlen);
376 strcpy (nonce + lfdirlen, nonce_base);
377
378 fd = mkostemp (nonce, O_BINARY | O_CLOEXEC);
379 if (fd < 0)
380 err = errno;
381 else
382 {
383 ptrdiff_t lock_info_len;
384 lock_info_len = strlen (lock_info_str);
385 err = 0;
386
387
388
389
390
391 if (emacs_write (fd, lock_info_str, lock_info_len) != lock_info_len
392 || fchmod (fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) != 0)
393 err = errno;
394
395
396
397 if (emacs_close (fd) != 0)
398 err = errno;
399 if (!err && rename_lock_file (nonce, lfname, force) != 0)
400 err = errno;
401 if (err)
402 unlink (nonce);
403 }
404
405 SAFE_FREE ();
406 }
407
408 return err;
409 }
410
411
412
413
414
415 static int
416 lock_file_1 (Lisp_Object lfname, bool force)
417 {
418 intmax_t boot = get_boot_time ();
419 Lisp_Object luser_name = Fuser_login_name (Qnil);
420 Lisp_Object lhost_name = Fsystem_name ();
421
422
423
424 if (!NILP (lhost_name) && strchr (SSDATA (lhost_name), '@'))
425 lhost_name = CALLN (Ffuncall, intern ("string-replace"),
426 build_string ("@"), build_string ("-"),
427 lhost_name);
428
429 char const *user_name = STRINGP (luser_name) ? SSDATA (luser_name) : "";
430 char const *host_name = STRINGP (lhost_name) ? SSDATA (lhost_name) : "";
431 char lock_info_str[MAX_LFINFO + 1];
432 intmax_t pid = getpid ();
433
434 if (boot)
435 {
436 if (sizeof lock_info_str
437 <= snprintf (lock_info_str, sizeof lock_info_str,
438 "%s@%s.%"PRIdMAX":%"PRIdMAX,
439 user_name, host_name, pid, boot))
440 return ENAMETOOLONG;
441 }
442 else if (sizeof lock_info_str
443 <= snprintf (lock_info_str, sizeof lock_info_str,
444 "%s@%s.%"PRIdMAX,
445 user_name, host_name, pid))
446 return ENAMETOOLONG;
447
448 return create_lock_file (SSDATA (lfname), lock_info_str, force);
449 }
450
451
452
453 static bool
454 within_one_second (time_t a, time_t b)
455 {
456 return (a - b >= -1 && a - b <= 1);
457 }
458
459
460 #ifndef ELOOP
461 # define ELOOP (-1)
462 #endif
463
464
465
466
467
468 static ptrdiff_t
469 read_lock_data (char *lfname, char lfinfo[MAX_LFINFO + 1])
470 {
471 ptrdiff_t nbytes;
472
473 while ((nbytes = readlinkat (AT_FDCWD, lfname, lfinfo, MAX_LFINFO + 1)) < 0
474 && errno == EINVAL)
475 {
476 int fd = emacs_open (lfname, O_RDONLY | O_NOFOLLOW, 0);
477 if (0 <= fd)
478 {
479 ptrdiff_t read_bytes = emacs_read (fd, lfinfo, MAX_LFINFO + 1);
480 int read_errno = errno;
481 if (emacs_close (fd) != 0)
482 return -1;
483 errno = read_errno;
484 return read_bytes;
485 }
486
487 if (errno != ELOOP)
488 return -1;
489
490
491
492
493 maybe_quit ();
494 }
495
496 return nbytes;
497 }
498
499
500
501 enum { NEGATIVE_ERRNO = EDOM < 0 };
502
503
504 enum
505 {
506
507 ANOTHER_OWNS_IT = NEGATIVE_ERRNO ? 1 : -1,
508
509
510 I_OWN_IT = 2 * ANOTHER_OWNS_IT
511 };
512
513
514
515
516
517
518
519 static int
520 current_lock_owner (lock_info_type *owner, Lisp_Object lfname)
521 {
522 lock_info_type local_owner;
523 ptrdiff_t lfinfolen;
524 intmax_t pid, boot_time;
525 char *at, *dot, *lfinfo_end;
526
527
528
529 if (!owner)
530 owner = &local_owner;
531
532
533 lfinfolen = read_lock_data (SSDATA (lfname), owner->user);
534 if (lfinfolen < 0)
535 return errno == ENOENT || errno == ENOTDIR ? 0 : errno;
536 if (MAX_LFINFO < lfinfolen)
537 return ENAMETOOLONG;
538 owner->user[lfinfolen] = 0;
539
540
541
542 owner->at = at = memrchr (owner->user, '@', lfinfolen);
543 if (!at)
544 return EINVAL;
545 owner->dot = dot = strrchr (at, '.');
546 if (!dot)
547 return EINVAL;
548
549
550 if (! c_isdigit (dot[1]))
551 return EINVAL;
552 errno = 0;
553 pid = strtoimax (dot + 1, &owner->colon, 10);
554 if (errno == ERANGE)
555 pid = -1;
556
557
558 char *boot = owner->colon + 1;
559 switch (owner->colon[0])
560 {
561 case 0:
562 boot_time = 0;
563 lfinfo_end = owner->colon;
564 break;
565
566 case '\357':
567
568
569
570
571 if (! (boot[0] == '\200' && boot[1] == '\242'))
572 return EINVAL;
573 boot += 2;
574 FALLTHROUGH;
575 case ':':
576 if (! c_isdigit (boot[0]))
577 return EINVAL;
578 boot_time = strtoimax (boot, &lfinfo_end, 10);
579 break;
580
581 default:
582 return EINVAL;
583 }
584 if (lfinfo_end != owner->user + lfinfolen)
585 return EINVAL;
586
587 Lisp_Object system_name = Fsystem_name ();
588
589
590
591 if (NILP (system_name))
592 system_name = build_string ("");
593
594
595 else if (strchr (SSDATA (system_name), '@'))
596 system_name = CALLN (Ffuncall, intern ("string-replace"),
597 build_string ("@"), build_string ("-"),
598 system_name);
599
600 if (STRINGP (system_name)
601 && dot - (at + 1) == SBYTES (system_name)
602 && memcmp (at + 1, SSDATA (system_name), SBYTES (system_name)) == 0)
603 {
604 if (pid == getpid ())
605 return I_OWN_IT;
606 else if (0 < pid && pid <= TYPE_MAXIMUM (pid_t)
607 && (kill (pid, 0) >= 0 || errno == EPERM)
608 && (boot_time == 0
609 || (boot_time <= TYPE_MAXIMUM (time_t)
610 && within_one_second (boot_time, get_boot_time ()))))
611 return ANOTHER_OWNS_IT;
612
613
614 else
615 return unlink (SSDATA (lfname)) < 0 ? errno : 0;
616 }
617 else
618 {
619
620 return ANOTHER_OWNS_IT;
621 }
622 }
623
624
625
626
627
628
629
630
631 static int
632 lock_if_free (lock_info_type *clasher, Lisp_Object lfname)
633 {
634 int err;
635 while ((err = lock_file_1 (lfname, 0)) == EEXIST)
636 {
637 err = current_lock_owner (clasher, lfname);
638
639
640
641 if (err != 0)
642 return err == I_OWN_IT ? 0 : err;
643
644
645
646 }
647
648 return err;
649 }
650
651
652
653 static Lisp_Object
654 make_lock_file_name (Lisp_Object fn)
655 {
656 Lisp_Object lock_file_name = call1 (Qmake_lock_file_name,
657 Fexpand_file_name (fn, Qnil));
658 return !NILP (lock_file_name) ? ENCODE_FILE (lock_file_name) : Qnil;
659 }
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679 static Lisp_Object
680 lock_file (Lisp_Object fn)
681 {
682 lock_info_type lock_info;
683
684
685
686
687 if (will_dump_p ())
688 return Qnil;
689
690 Lisp_Object lfname = Qnil;
691 if (create_lockfiles)
692 {
693
694 lfname = make_lock_file_name (fn);
695 if (NILP (lfname))
696 return Qnil;
697 }
698
699
700
701 Lisp_Object subject_buf = get_truename_buffer (fn);
702 if (!NILP (subject_buf)
703 && NILP (Fverify_visited_file_modtime (subject_buf))
704 && !NILP (Ffile_exists_p (fn))
705 && !(!NILP (lfname) && current_lock_owner (NULL, lfname) == I_OWN_IT))
706 call1 (intern ("userlock--ask-user-about-supersession-threat"), fn);
707
708
709 if (!NILP (lfname))
710 {
711
712
713 if (lock_if_free (&lock_info, lfname) == ANOTHER_OWNS_IT)
714 {
715
716 Lisp_Object attack;
717 char *dot = lock_info.dot;
718 ptrdiff_t pidlen = lock_info.colon - (dot + 1);
719 static char const replacement[] = " (pid ";
720 int replacementlen = sizeof replacement - 1;
721 memmove (dot + replacementlen, dot + 1, pidlen);
722 strcpy (dot + replacementlen + pidlen, ")");
723 memcpy (dot, replacement, replacementlen);
724 attack = call2 (intern ("ask-user-about-lock"), fn,
725 build_string (lock_info.user));
726
727 if (!NILP (attack))
728 lock_file_1 (lfname, 1);
729 }
730 }
731 return Qnil;
732 }
733
734 static Lisp_Object
735 unlock_file (Lisp_Object fn)
736 {
737 Lisp_Object lfname = make_lock_file_name (fn);
738 if (NILP (lfname))
739 return Qnil;
740
741 int err = current_lock_owner (0, lfname);
742 if (! (err == 0 || err == ANOTHER_OWNS_IT
743 || (err == I_OWN_IT
744 && (unlink (SSDATA (lfname)) == 0 || (err = errno) == ENOENT))))
745 report_file_errno ("Unlocking file", fn, err);
746
747 return Qnil;
748 }
749
750 static Lisp_Object
751 unlock_file_handle_error (Lisp_Object err)
752 {
753 call1 (intern ("userlock--handle-unlock-error"), err);
754 return Qnil;
755 }
756
757 #endif
758
759 void
760 unlock_all_files (void)
761 {
762 register Lisp_Object tail, buf;
763 register struct buffer *b;
764
765 FOR_EACH_LIVE_BUFFER (tail, buf)
766 {
767 b = XBUFFER (buf);
768 if (STRINGP (BVAR (b, file_truename))
769 && BUF_SAVE_MODIFF (b) < BUF_MODIFF (b))
770 Funlock_file (BVAR (b, file_truename));
771 }
772 }
773
774 DEFUN ("lock-file", Flock_file, Slock_file, 1, 1, 0,
775 doc:
776 )
777 (Lisp_Object file)
778 {
779 #ifndef MSDOS
780 CHECK_STRING (file);
781
782
783
784 Lisp_Object handler;
785 handler = Ffind_file_name_handler (file, Qlock_file);
786 if (!NILP (handler))
787 return call2 (handler, Qlock_file, file);
788
789 lock_file (file);
790 #endif
791 return Qnil;
792 }
793
794 DEFUN ("unlock-file", Funlock_file, Sunlock_file, 1, 1, 0,
795 doc: )
796 (Lisp_Object file)
797 {
798 #ifndef MSDOS
799 CHECK_STRING (file);
800
801
802
803 Lisp_Object handler;
804 handler = Ffind_file_name_handler (file, Qunlock_file);
805 if (!NILP (handler))
806 {
807 call2 (handler, Qunlock_file, file);
808 return Qnil;
809 }
810
811 internal_condition_case_1 (unlock_file,
812 file,
813 list1 (Qfile_error),
814 unlock_file_handle_error);
815 #endif
816 return Qnil;
817 }
818
819 DEFUN ("lock-buffer", Flock_buffer, Slock_buffer,
820 0, 1, 0,
821 doc:
822
823
824
825 )
826 (Lisp_Object file)
827 {
828 if (NILP (file))
829 file = BVAR (current_buffer, file_truename);
830 else
831 CHECK_STRING (file);
832 if (SAVE_MODIFF < MODIFF
833 && !NILP (file))
834 Flock_file (file);
835 return Qnil;
836 }
837
838 DEFUN ("unlock-buffer", Funlock_buffer, Sunlock_buffer,
839 0, 0, 0,
840 doc:
841
842
843
844
845 )
846 (void)
847 {
848 if (SAVE_MODIFF < MODIFF
849 && STRINGP (BVAR (current_buffer, file_truename)))
850 Funlock_file (BVAR (current_buffer, file_truename));
851 return Qnil;
852 }
853
854
855
856 void
857 unlock_buffer (struct buffer *buffer)
858 {
859 if (BUF_SAVE_MODIFF (buffer) < BUF_MODIFF (buffer)
860 && STRINGP (BVAR (buffer, file_truename)))
861 Funlock_file (BVAR (buffer, file_truename));
862 }
863
864 DEFUN ("file-locked-p", Ffile_locked_p, Sfile_locked_p, 1, 1, 0,
865 doc:
866
867 )
868 (Lisp_Object filename)
869 {
870 #ifdef MSDOS
871 return Qnil;
872 #else
873 Lisp_Object ret;
874 int owner;
875 lock_info_type locker;
876
877
878
879 Lisp_Object handler;
880 handler = Ffind_file_name_handler (filename, Qfile_locked_p);
881 if (!NILP (handler))
882 {
883 return call2 (handler, Qfile_locked_p, filename);
884 }
885
886 Lisp_Object lfname = make_lock_file_name (filename);
887 if (NILP (lfname))
888 return Qnil;
889
890 owner = current_lock_owner (&locker, lfname);
891 switch (owner)
892 {
893 case I_OWN_IT: ret = Qt; break;
894 case ANOTHER_OWNS_IT:
895 ret = make_string (locker.user, locker.at - locker.user);
896 break;
897 case 0: ret = Qnil; break;
898 default: report_file_errno ("Testing file lock", filename, owner);
899 }
900
901 return ret;
902 #endif
903 }
904
905 void
906 syms_of_filelock (void)
907 {
908 DEFVAR_LISP ("temporary-file-directory", Vtemporary_file_directory,
909 doc: );
910 Vtemporary_file_directory = Qnil;
911
912 DEFVAR_BOOL ("create-lockfiles", create_lockfiles,
913 doc:
914
915
916 );
917 create_lockfiles = true;
918
919 DEFSYM (Qlock_file, "lock-file");
920 DEFSYM (Qunlock_file, "unlock-file");
921 DEFSYM (Qfile_locked_p, "file-locked-p");
922 DEFSYM (Qmake_lock_file_name, "make-lock-file-name");
923
924 defsubr (&Slock_file);
925 defsubr (&Sunlock_file);
926 defsubr (&Slock_buffer);
927 defsubr (&Sunlock_buffer);
928 defsubr (&Sfile_locked_p);
929 }