1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23: #include <config.h>
24: #include <sys/types.h>
25: #include <sys/stat.h>
26: #include <signal.h>
27: #include <stdio.h>
28:
29: #ifdef HAVE_PWD_H
30: #include <pwd.h>
31: #endif
32:
33: #include <sys/file.h>
34: #ifdef HAVE_FCNTL_H
35: #include <fcntl.h>
36: #endif
37: #ifdef HAVE_STRING_H
38: #include <string.h>
39: #endif
40:
41: #ifdef HAVE_UNISTD_H
42: #include <unistd.h>
43: #endif
44:
45: #ifdef __FreeBSD__
46: #include <sys/sysctl.h>
47: #endif
48:
49: #include <errno.h>
50: #ifndef errno
51: extern int errno;
52: #endif
53:
54: #include "lisp.h"
55: #include "buffer.h"
56: #include "charset.h"
57: #include "coding.h"
58: #include "systime.h"
59:
60:
61:
62: Lisp_Object Vtemporary_file_directory;
63:
64: #ifdef CLASH_DETECTION
65:
66: #include <utmp.h>
67:
68: #if !defined (S_ISLNK) && defined (S_IFLNK)
69: #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
70: #endif
71:
72:
73:
74: #ifndef BOOT_TIME_FILE
75: #define BOOT_TIME_FILE "/var/run/random-seed"
76: #endif
77:
78: #ifndef WTMP_FILE
79: #define WTMP_FILE "/var/log/wtmp"
80: #endif
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: ^L
118:
119:
120: static time_t boot_time;
121: static int boot_time_initialized;
122:
123: extern Lisp_Object Vshell_file_name;
124:
125: #ifdef BOOT_TIME
126: static void get_boot_time_1 P_ ((char *, int));
127: #endif
128:
129: static time_t
130: get_boot_time ()
131: {
132: #if defined (BOOT_TIME) && ! defined (NO_WTMP_FILE)
133: int counter;
134: #endif
135:
136: if (boot_time_initialized)
137: return boot_time;
138: boot_time_initialized = 1;
139:
140: #if defined (CTL_KERN) && defined (KERN_BOOTTIME)
141: {
142: int mib[2];
143: size_t size;
144: struct timeval boottime_val;
145:
146: mib[0] = CTL_KERN;
147: mib[1] = KERN_BOOTTIME;
148: size = sizeof (boottime_val);
149:
150: if (sysctl (mib, 2, &boottime_val, &size, NULL, 0) >= 0)
151: {
152: boot_time = boottime_val.tv_sec;
153: return boot_time;
154: }
155: }
156: #endif
157:
158: if (BOOT_TIME_FILE)
159: {
160: struct stat st;
161: if (stat (BOOT_TIME_FILE, &st) == 0)
162: {
163: boot_time = st.st_mtime;
164: return boot_time;
165: }
166: }
167:
168: #if defined (BOOT_TIME) && ! defined (NO_WTMP_FILE)
169: #ifndef CANNOT_DUMP
170:
171:
172:
173: if (! initialized)
174: return boot_time;
175: #endif
176:
177:
178:
179:
180:
181: get_boot_time_1 ((char *) 0, 0);
182: if (boot_time)
183: return boot_time;
184:
185:
186: get_boot_time_1 (WTMP_FILE, 1);
187:
188:
189: for (counter = 0; counter < 20 && ! boot_time; counter++)
190: {
191: char cmd_string[100];
192: Lisp_Object tempname, filename;
193: int delete_flag = 0;
194:
195: filename = Qnil;
196:
197: sprintf (cmd_string, "%s.%d", WTMP_FILE, counter);
198: tempname = build_string (cmd_string);
199: if (! NILP (Ffile_exists_p (tempname)))
200: filename = tempname;
201: else
202: {
203: sprintf (cmd_string, "%s.%d.gz", WTMP_FILE, counter);
204: tempname = build_string (cmd_string);
205: if (! NILP (Ffile_exists_p (tempname)))
206: {
207: Lisp_Object args[6];
208:
209:
210:
211:
212:
213:
214: tempname = Fexpand_file_name (build_string ("wt"),
215: Vtemporary_file_directory);
216: tempname = make_temp_name (tempname, 1);
217: args[0] = Vshell_file_name;
218: args[1] = Qnil;
219: args[2] = Qnil;
220: args[3] = Qnil;
221: args[4] = build_string ("-c");
222: sprintf (cmd_string, "gunzip < %s.%d.gz > %s",
223: WTMP_FILE, counter, SDATA (tempname));
224: args[5] = build_string (cmd_string);
225: Fcall_process (6, args);
226: filename = tempname;
227: delete_flag = 1;
228: }
229: }
230:
231: if (! NILP (filename))
232: {
233: get_boot_time_1 (SDATA (filename), 1);
234: if (delete_flag)
235: unlink (SDATA (filename));
236: }
237: }
238:
239: return boot_time;
240: #else
241: return 0;
242: #endif
243: }
244:
245: #ifdef BOOT_TIME
246:
247:
248:
249:
250:
251:
252:
253:
254:
255:
256: void
257: get_boot_time_1 (filename, newest)
258: char *filename;
259: int newest;
260: {
261: struct utmp ut, *utp;
262: int desc;
263:
264: if (filename)
265: {
266:
267:
268: desc = emacs_open (filename, O_RDONLY, 0);
269: if (desc < 0)
270: return;
271:
272: emacs_close (desc);
273:
274: utmpname (filename);
275: }
276:
277: setutent ();
278:
279: while (1)
280: {
281:
282: ut.ut_type = BOOT_TIME;
283: utp = getutid (&ut);
284: if (! utp)
285: break;
286:
287: if (utp->ut_time > boot_time)
288: {
289: boot_time = utp->ut_time;
290: if (! newest)
291: break;
292: }
293:
294:
295: utp = getutent ();
296: if (! utp)
297: break;
298: }
299: endutent ();
300: }
301: #endif
302: ^L
303:
304:
305: typedef struct
306: {
307: char *user;
308: char *host;
309: unsigned long pid;
310: time_t boot_time;
311: } lock_info_type;
312:
313:
314:
315: #define LOCK_PID_MAX (4 * sizeof (unsigned long))
316:
317:
318: #define FREE_LOCK_INFO(i) do { xfree ((i).user); xfree ((i).host); } while (0)
319:
320:
321:
322:
323:
324:
325: #define MAKE_LOCK_NAME(lock, file) \
326: (lock = (char *) alloca (SBYTES (file) + 2 + 1 + 1 + 1), \
327: fill_in_lock_file_name (lock, (file)))
328:
329: static void
330: fill_in_lock_file_name (lockfile, fn)
331: register char *lockfile;
332: register Lisp_Object fn;
333: {
334: register char *p;
335: struct stat st;
336: int count = 0;
337:
338: strcpy (lockfile, SDATA (fn));
339:
340:
341:
342:
343: for (p = lockfile + strlen (lockfile); p != lockfile && *p != '/'; p--)
344: p[2] = *p;
345:
346:
347: p[1] = '.';
348: p[2] = '#';
349:
350: p = p + strlen (p);
351:
352: while (lstat (lockfile, &st) == 0 && !S_ISLNK (st.st_mode))
353: {
354: if (count > 9)
355: {
356: *p = '\0';
357: return;
358: }
359: sprintf (p, ".%d", count++);
360: }
361: }
362:
363:
364:
365:
366:
367: static int
368: lock_file_1 (lfname, force)
369: char *lfname;
370: int force;
371: {
372: register int err;
373: time_t boot_time;
374: char *user_name;
375: char *host_name;
376: char *lock_info_str;
377:
378:
379: boot_time = get_boot_time ();
380:
381: if (STRINGP (Fuser_login_name (Qnil)))
382: user_name = (char *)SDATA (Fuser_login_name (Qnil));
383: else
384: user_name = "";
385: if (STRINGP (Fsystem_name ()))
386: host_name = (char *)SDATA (Fsystem_name ());
387: else
388: host_name = "";
389: lock_info_str = (char *)alloca (strlen (user_name) + strlen (host_name)
390: + LOCK_PID_MAX + 30);
391:
392: if (boot_time)
393: sprintf (lock_info_str, "%s@%s.%lu:%lu", user_name, host_name,
394: (unsigned long) getpid (), (unsigned long) boot_time);
395: else
396: sprintf (lock_info_str, "%s@%s.%lu", user_name, host_name,
397: (unsigned long) getpid ());
398:
399: err = symlink (lock_info_str, lfname);
400: if (errno == EEXIST && force)
401: {
402: unlink (lfname);
403: err = symlink (lock_info_str, lfname);
404: }
405:
406: return err == 0;
407: }
408:
409:
410:
411: int
412: within_one_second (a, b)
413: time_t a, b;
414: {
415: return (a - b >= -1 && a - b <= 1);
416: }
417: ^L
418:
419:
420:
421:
422:
423: static int
424: current_lock_owner (owner, lfname)
425: lock_info_type *owner;
426: char *lfname;
427: {
428: #ifndef index
429: extern char *rindex (), *index ();
430: #endif
431: int len, ret;
432: int local_owner = 0;
433: char *at, *dot, *colon;
434: char *lfinfo = 0;
435: int bufsize = 50;
436:
437:
438: do
439: {
440: bufsize *= 2;
441: lfinfo = (char *) xrealloc (lfinfo, bufsize);
442: errno = 0;
443: len = readlink (lfname, lfinfo, bufsize);
444: #ifdef ERANGE
445:
446: if (len == -1 && errno == ERANGE)
447: len = bufsize;
448: #endif
449: }
450: while (len >= bufsize);
451:
452:
453: if (len == -1)
454: {
455: xfree (lfinfo);
456: return errno == ENOENT ? 0 : -1;
457: }
458:
459:
460: lfinfo[len] = 0;
461:
462:
463:
464: if (!owner)
465: {
466: owner = (lock_info_type *) alloca (sizeof (lock_info_type));
467: local_owner = 1;
468: }
469:
470:
471:
472: at = index (lfinfo, '@');
473: dot = rindex (lfinfo, '.');
474: if (!at || !dot)
475: {
476: xfree (lfinfo);
477: return -1;
478: }
479: len = at - lfinfo;
480: owner->user = (char *) xmalloc (len + 1);
481: strncpy (owner->user, lfinfo, len);
482: owner->user[len] = 0;
483:
484:
485: owner->pid = atoi (dot + 1);
486: colon = dot;
487: while (*colon && *colon != ':')
488: colon++;
489:
490: if (*colon == ':')
491: owner->boot_time = atoi (colon + 1);
492: else
493: owner->boot_time = 0;
494:
495:
496: len = dot - at - 1;
497: owner->host = (char *) xmalloc (len + 1);
498: strncpy (owner->host, at + 1, len);
499: owner->host[len] = 0;
500:
501:
502: xfree (lfinfo);
503:
504:
505: if (STRINGP (Fsystem_name ())
506: && strcmp (owner->host, SDATA (Fsystem_name ())) == 0)
507: {
508: if (owner->pid == getpid ())
509: ret = 2;
510: else if (owner->pid > 0
511: && (kill (owner->pid, 0) >= 0 || errno == EPERM)
512: && (owner->boot_time == 0
513: || within_one_second (owner->boot_time, get_boot_time ())))
514: ret = 1;
515:
516:
517: else if (unlink (lfname) < 0)
518: ret = -1;
519: else
520: ret = 0;
521: }
522: else
523: {
524:
525: ret = 1;
526: }
527:
528:
529: if (local_owner || ret <= 0)
530: {
531: FREE_LOCK_INFO (*owner);
532: }
533: return ret;
534: }
535:
536: ^L
537:
538:
539:
540:
541:
542:
543: static int
544: lock_if_free (clasher, lfname)
545: lock_info_type *clasher;
546: register char *lfname;
547: {
548: while (lock_file_1 (lfname, 0) == 0)
549: {
550: int locker;
551:
552: if (errno != EEXIST)
553: return -1;
554:
555: locker = current_lock_owner (clasher, lfname);
556: if (locker == 2)
557: {
558: FREE_LOCK_INFO (*clasher);
559: return 0;
560: }
561: else if (locker == 1)
562: return 1;
563: else if (locker == -1)
564: return -1;
565:
566:
567: }
568: return 0;
569: }
570:
571:
572:
573:
574:
575:
576:
577:
578:
579:
580:
581:
582:
583:
584:
585:
586:
587:
588: void
589: lock_file (fn)
590: Lisp_Object fn;
591: {
592: register Lisp_Object attack, orig_fn, encoded_fn;
593: register char *lfname, *locker;
594: lock_info_type lock_info;
595: struct gcpro gcpro1;
596:
597:
598:
599:
600: if (! NILP (Vpurify_flag))
601: return;
602:
603: orig_fn = fn;
604: GCPRO1 (fn);
605: fn =