1/* lock.c
2   Lock and unlock a file name.
3
4   Copyright (C) 1991, 1992, 1993, 1995, 2002 Ian Lance Taylor
5
6   This file is part of the Taylor UUCP package.
7
8   This program is free software; you can redistribute it and/or
9   modify it under the terms of the GNU General Public License as
10   published by the Free Software Foundation; either version 2 of the
11   License, or (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16   General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software
20   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
21
22   The author of the program may be contacted at ian@airs.com.
23   */
24
25#include "uucp.h"
26
27#if USE_RCS_ID
28const char lock_rcsid[] = "$Id: lock.c,v 1.23 2002/03/05 19:10:42 ian Rel $";
29#endif
30
31#include "uudefs.h"
32#include "sysdep.h"
33#include "system.h"
34
35#include <errno.h>
36#include <ctype.h>
37
38#if HAVE_FCNTL_H
39#include <fcntl.h>
40#else
41#if HAVE_SYS_FILE_H
42#include <sys/file.h>
43#endif
44#endif
45
46#if TM_IN_SYS_TIME
47#include <sys/time.h>
48#else
49#include <time.h>
50#endif
51
52#if HAVE_QNX_LOCKFILES
53#include <sys/kernel.h>
54#include <sys/psinfo.h>
55#include <sys/seginfo.h>
56#include <sys/vc.h>
57#endif
58
59#ifndef O_RDONLY
60#define O_RDONLY 0
61#define O_WRONLY 1
62#define O_RDWR 2
63#endif
64
65#ifndef O_NOCTTY
66#define O_NOCTTY 0
67#endif
68
69#ifndef SEEK_SET
70#define SEEK_SET 0
71#endif
72
73#ifndef localtime
74extern struct tm *localtime ();
75#endif
76
77#if HAVE_QNX_LOCKFILES
78static boolean fsqnx_stale P((unsigned long ipid, unsigned long inme,
79			     unsigned long inid, boolean *pferr));
80#endif
81
82/* Lock something.  If the fspooldir argument is TRUE, the argument is
83   a file name relative to the spool directory; otherwise the argument
84   is a simple file name which should be created in the system lock
85   directory (under HDB this is /etc/locks).  */
86
87boolean
88fsdo_lock (zlock, fspooldir, pferr)
89     const char *zlock;
90     boolean fspooldir;
91     boolean *pferr;
92{
93  char *zfree;
94  const char *zpath, *zslash;
95  size_t cslash;
96  pid_t ime;
97  char *ztempfile;
98  char abtempfile[sizeof "TMP12345678901234567890"];
99  int o;
100#if HAVE_QNX_LOCKFILES
101  nid_t inme;
102  char ab[23];
103  char *zend;
104#else
105#if HAVE_V2_LOCKFILES
106  int i;
107#else
108  char ab[12];
109#endif
110#endif
111  int cwrote;
112  const char *zerr;
113  boolean fret;
114
115  if (pferr != NULL)
116    *pferr = TRUE;
117
118  if (fspooldir)
119    {
120      zfree = NULL;
121      zpath = zlock;
122    }
123  else
124    {
125      zfree = zsysdep_in_dir (zSlockdir, zlock);
126      zpath = zfree;
127    }
128
129  ime = getpid ();
130#if HAVE_QNX_LOCKFILES
131  inme = getnid ();
132#endif
133
134  /* We do the actual lock by creating a file and then linking it to
135     the final file name we want.  This avoids race conditions due to
136     one process checking the file before we have finished writing it,
137     and also works even if we are somehow running as root.
138
139     First, create the file in the right directory (we must create the
140     file in the same directory since otherwise we might attempt a
141     cross-device link).  */
142  zslash = strrchr (zpath, '/');
143  if (zslash == NULL)
144    cslash = 0;
145  else
146    cslash = zslash - zpath + 1;
147
148#if HAVE_QNX_LOCKFILES
149  sprintf (abtempfile, "TMP%010lx%010lx", (unsigned long) ime,
150	   (unsigned long) inme);
151#else
152  sprintf (abtempfile, "TMP%010lx", (unsigned long) ime);
153#endif
154  ztempfile = zbufalc (cslash + sizeof abtempfile);
155  memcpy (ztempfile, zpath, cslash);
156  memcpy (ztempfile + cslash, abtempfile, sizeof abtempfile);
157
158  o = creat (ztempfile, IPUBLIC_FILE_MODE);
159  if (o < 0)
160    {
161      if (errno == ENOENT)
162	{
163	  if (! fsysdep_make_dirs (ztempfile, FALSE))
164	    {
165	      ubuffree (zfree);
166	      ubuffree (ztempfile);
167	      return FALSE;
168	    }
169	  o = creat (ztempfile, IPUBLIC_FILE_MODE);
170	}
171      if (o < 0)
172	{
173	  ulog (LOG_ERROR, "creat during lock (%s in %s as uid %d): %s", ztempfile, getwd(NULL), getuid(), strerror (errno));
174	  ubuffree (zfree);
175	  ubuffree (ztempfile);
176	  return FALSE;
177	}
178    }
179
180#if HAVE_QNX_LOCKFILES
181  sprintf (ab, "%10ld %10ld\n", (long) ime, (long) inme);
182  cwrote = write (o, ab, strlen (ab));
183#else
184#if HAVE_V2_LOCKFILES
185  i = (int) ime;
186  cwrote = write (o, &i, sizeof i);
187#else
188  sprintf (ab, "%10ld\n", (long) ime);
189  cwrote = write (o, ab, strlen (ab));
190#endif
191#endif
192
193  zerr = NULL;
194  if (cwrote < 0)
195    zerr = "write";
196  if (close (o) < 0)
197    zerr = "close";
198  if (zerr != NULL)
199    {
200      ulog (LOG_ERROR, "%s (%s): %s", zerr, ztempfile, strerror (errno));
201      (void) remove (ztempfile);
202      ubuffree (zfree);
203      ubuffree (ztempfile);
204      return FALSE;
205    }
206
207  /* Now try to link the file we just created to the lock file that we
208     want.  If it fails, try reading the existing file to make sure
209     the process that created it still exists.  We do this in a loop
210     to make it easy to retry if the old locking process no longer
211     exists.  */
212  fret = TRUE;
213  if (pferr != NULL)
214    *pferr = FALSE;
215  o = -1;
216  zerr = NULL;
217
218  while (link (ztempfile, zpath) != 0)
219    {
220      int cgot;
221      pid_t ipid;
222      boolean freadonly;
223      struct stat st;
224      char abtime[sizeof "1991-12-31 12:00:00"];
225#if HAVE_QNX_LOCKFILES
226      nid_t inid;
227#endif
228
229      fret = FALSE;
230
231      if (errno != EEXIST)
232	{
233	  ulog (LOG_ERROR, "link (%s, %s): %s", ztempfile, zpath,
234		strerror (errno));
235	  if (pferr != NULL)
236	    *pferr = TRUE;
237	  break;
238	}
239
240      freadonly = FALSE;
241      o = open ((char *) zpath, O_RDWR | O_NOCTTY, 0);
242      if (o < 0)
243	{
244	  if (errno == EACCES)
245	    {
246	      freadonly = TRUE;
247	      o = open ((char *) zpath, O_RDONLY, 0);
248	    }
249	  if (o < 0)
250	    {
251	      if (errno == ENOENT)
252		{
253		  /* The file was presumably removed between the link
254		     and the open.  Try the link again.  */
255		  fret = TRUE;
256		  continue;
257		}
258	      zerr = "open";
259	      break;
260	    }
261	}
262
263      /* The race starts here.  See below for a discussion.  */
264
265#if HAVE_V2_LOCKFILES
266      cgot = read (o, &i, sizeof i);
267#else
268      cgot = read (o, ab, sizeof ab - 1);
269#endif
270
271      if (cgot < 0)
272	{
273	  zerr = "read";
274	  break;
275	}
276
277#if DEBUG > 0
278#if HAVE_V2_LOCKFILES
279      {
280	char ab[10];
281
282	if (read (o, ab, sizeof ab) > 4
283	    && isdigit (BUCHAR (ab[0])))
284	  ulog (LOG_ERROR,
285		"Lock file %s may be HDB format; check LOCKFILES in policy.h",
286		zpath);
287      }
288#else
289      if (cgot == 4)
290	ulog (LOG_ERROR,
291	      "Lock file %s may be V2 format; check LOCKFILES in policy.h",
292	      zpath);
293#endif
294#endif /* DEBUG > 0 */
295
296#if HAVE_QNX_LOCKFILES
297      ab[cgot] = '\0';
298      ipid = (pid_t) strtol (ab, &zend, 10);
299      inid = (nid_t) strtol (zend, (char **) NULL, 10);
300#else
301#if HAVE_V2_LOCKFILES
302      ipid = (pid_t) i;
303#else
304      ab[cgot] = '\0';
305      ipid = (pid_t) strtol (ab, (char **) NULL, 10);
306#endif
307#endif
308
309      /* On NFS, the link might have actually succeeded even though we
310	 got a failure return.  This can happen if the original
311	 acknowledgement was lost or delayed and the operation was
312	 retried.  In this case the pid will be our own.  This
313	 introduces a rather improbable race condition: if a stale
314	 lock was left with our process ID in it, and another process
315	 just did the kill, below, but has not yet changed the lock
316	 file to hold its own process ID, we could start up and make
317	 it all the way to here and think we have the lock.  I'm not
318	 going to worry about this possibility.  */
319      if (ipid == ime)
320	{
321#if HAVE_QNX_LOCKFILES
322	  if (inid == inme)
323#endif
324	    {
325	      fret = TRUE;
326	      break;
327	    }
328	}
329
330      /* If the lock file is empty (cgot == 0), we assume that it is
331         stale.  This can happen if the system crashed after the lock
332         file was created but before the process ID was written out.  */
333      if (cgot > 0)
334	{
335#if HAVE_QNX_LOCKFILES
336	  if (! fsqnx_stale ((unsigned long) ipid, (unsigned long) inme,
337			     (unsigned long) inid, pferr))
338	    break;
339#else
340	  /* If the process still exists, we will get EPERM rather
341	     than ESRCH.  We then return FALSE to indicate that we
342	     cannot make the lock.  */
343	  if (kill (ipid, 0) == 0 || errno == EPERM)
344	    break;
345#endif
346	}
347
348      if (fstat (o, &st) < 0)
349	strcpy (abtime, "unknown");
350      else
351	{
352	  time_t itm;
353	  struct tm *q;
354
355	  itm = (time_t) st.st_mtime;
356	  q = localtime (&itm);
357	  sprintf (abtime, "%04d-%02d-%02d %02d:%02d:%02d",
358		   q->tm_year + 1900, q->tm_mon + 1, q->tm_mday, q->tm_hour,
359		   q->tm_min, q->tm_sec);
360	}
361
362#if HAVE_QNX_LOCKFILES
363      ulog (LOG_ERROR,
364	    "Stale lock %s held by process %ld on node %ld created %s",
365	    zpath, (long) ipid, (long) inid, abtime);
366#else
367      ulog (LOG_ERROR, "Stale lock %s held by process %ld created %s",
368	    zpath, (long) ipid, abtime);
369#endif
370
371      /* This is a stale lock, created by a process that no longer
372	 exists.
373
374	 Now we could remove the file (and, if the file mode disallows
375	 writing, that's what we have to do), but we try to avoid
376	 doing so since it causes a race condition.  If we remove the
377	 file, and are interrupted any time after we do the read until
378	 we do the remove, another process could get in, open the
379	 file, find that it was a stale lock, remove the file and
380	 create a new one.  When we regained control we would remove
381	 the file the other process just created.
382
383	 These files are being generated partially for the benefit of
384	 cu, and it would be nice to avoid the race however cu avoids
385	 it, so that the programs remain compatible.  Unfortunately,
386	 nobody seems to know how cu avoids the race, or even if it
387	 tries to avoid it at all.
388
389	 There are a few ways to avoid the race.  We could use kernel
390	 locking primitives, but they may not be available.  We could
391	 link to a special file name, but if that file were left lying
392	 around then no stale lock could ever be broken (Henry Spencer
393	 would think this was a good thing).
394
395	 Instead I've implemented the following procedure: seek to the
396	 start of the file, write our pid into it, sleep for five
397	 seconds, and then make sure our pid is still there.  Anybody
398	 who checks the file while we're asleep will find our pid
399	 there and fail the lock.  The only race will come from
400	 another process which has done the read by the time we do our
401	 write.  That process will then have five seconds to do its
402	 own write.  When we wake up, we'll notice that our pid is no
403	 longer in the file, and retry the lock from the beginning.
404
405	 This relies on the atomicity of write(2).  If it possible for
406	 the writes of two processes to be interleaved, the two
407	 processes could livelock.  POSIX unfortunately leaves this
408	 case explicitly undefined; however, given that the write is
409	 of less than a disk block, it's difficult to imagine an
410	 interleave occurring.
411
412	 Note that this is still a race.  If it takes the second
413	 process more than five seconds to do the kill, the lseek, and
414	 the write, both processes will think they have the lock.
415	 Perhaps the length of time to sleep should be configurable.
416	 Even better, perhaps I should add a configuration option to
417	 use a permanent lock file, which eliminates any race and
418	 forces the installer to be aware of the existence of the
419	 permanent lock file.
420
421	 We stat the file after the sleep, to make sure some other
422	 program hasn't deleted it for us.  */
423      if (freadonly)
424	{
425	  (void) close (o);
426	  o = -1;
427	  if (remove (zpath) != 0)
428	    {
429	      zerr = "remove";
430	      break;
431	    }
432	  fret = TRUE;
433	  continue;
434	}
435
436      if (lseek (o, (off_t) 0, SEEK_SET) != 0)
437	{
438	  zerr = "lseek";
439	  break;
440	}
441
442#if HAVE_QNX_LOCKFILES
443      sprintf (ab, "%10ld %10ld\n", (long) ime, (long) inme);
444      cwrote = write (o, ab, strlen (ab));
445#else
446#if HAVE_V2_LOCKFILES
447      i = (int) ime;
448      cwrote = write (o, &i, sizeof i);
449#else
450      sprintf (ab, "%10ld\n", (long) ime);
451      cwrote = write (o, ab, strlen (ab));
452#endif
453#endif
454
455      if (cwrote < 0)
456	{
457	  zerr = "write";
458	  break;
459	}
460
461      (void) sleep (5);
462
463      if (lseek (o, (off_t) 0, SEEK_SET) != 0)
464	{
465	  zerr = "lseek";
466	  break;
467	}
468
469#if HAVE_V2_LOCKFILES
470      cgot = read (o, &i, sizeof i);
471#else
472      cgot = read (o, ab, sizeof ab - 1);
473#endif
474
475      if (cgot < 0)
476	{
477	  zerr = "read";
478	  break;
479	}
480
481#if HAVE_QNX_LOCKFILES
482      ab[cgot] = '\0';
483      ipid = (pid_t) strtol (ab, &zend, 10);
484      inid = (nid_t) strtol (zend, (char **) NULL, 10);
485#else
486#if HAVE_V2_LOCKFILES
487      ipid = (pid_t) i;
488#else
489      ab[cgot] = '\0';
490      ipid = (pid_t) strtol (ab, (char **) NULL, 10);
491#endif
492#endif
493
494      if (ipid == ime)
495	{
496#if HAVE_QNX_LOCKFILES
497	  if (inid == inme)
498#endif
499	    {
500	      struct stat sfile, sdescriptor;
501
502	      /* It looks like we have the lock.  Do the final stat
503		 check.  */
504	      if (stat ((char *) zpath, &sfile) < 0)
505		{
506		  if (errno != ENOENT)
507		    {
508		      zerr = "stat";
509		      break;
510		    }
511		  /* Loop around and try again.  */
512		}
513	      else
514		{
515		  if (fstat (o, &sdescriptor) < 0)
516		    {
517		      zerr = "fstat";
518		      break;
519		    }
520
521		  if (sfile.st_ino == sdescriptor.st_ino
522		      && sfile.st_dev == sdescriptor.st_dev)
523		    {
524		      /* Close the file before assuming we've
525			 succeeded to pick up any trailing errors.  */
526		      if (close (o) < 0)
527			{
528			  zerr = "close";
529			  break;
530			}
531
532		      o = -1;
533
534		      /* We have the lock.  */
535		      fret = TRUE;
536		      break;
537		    }
538		}
539	    }
540	}
541
542      /* Loop around and try the lock again.  We keep doing this until
543	 the lock file holds a pid that exists.  */
544      (void) close (o);
545      o = -1;
546      fret = TRUE;
547    }
548
549  if (zerr != NULL)
550    {
551      ulog (LOG_ERROR, "%s (%s): %s", zerr, zpath, strerror (errno));
552      if (pferr != NULL)
553	*pferr = TRUE;
554    }
555
556  if (o >= 0)
557    (void) close (o);
558
559  ubuffree (zfree);
560
561  /* It would be nice if we could leave the temporary file around for
562     future calls, but considering that we create lock files in
563     various different directories it's probably more trouble than
564     it's worth.  */
565  if (remove (ztempfile) != 0)
566    ulog (LOG_ERROR, "remove (%s): %s", ztempfile, strerror (errno));
567
568  ubuffree (ztempfile);
569
570  return fret;
571}
572
573/* Unlock something.  The fspooldir argument is as in fsdo_lock.  */
574
575boolean
576fsdo_unlock (zlock, fspooldir)
577     const char *zlock;
578     boolean fspooldir;
579{
580  char *zfree;
581  const char *zpath;
582
583  if (fspooldir)
584    {
585      zfree = NULL;
586      zpath = zlock;
587    }
588  else
589    {
590      zfree = zsysdep_in_dir (zSlockdir, zlock);
591      zpath = zfree;
592    }
593
594  if (remove (zpath) == 0
595      || errno == ENOENT)
596    {
597      ubuffree (zfree);
598      return TRUE;
599    }
600  else
601    {
602      ulog (LOG_ERROR, "remove (%s): %s", zpath, strerror (errno));
603      ubuffree (zfree);
604      return FALSE;
605    }
606}
607
608#if HAVE_QNX_LOCKFILES
609
610/* Return TRUE if the lock is stale.  */
611
612static boolean
613fsqnx_stale (ipid, inme, inid, pferr)
614     unsigned long ipid;
615     unsigned long inme;
616     unsigned long inid;
617     boolean *pferr;
618{
619  /* A virtual process ID.  This virtual process ID, which will exist
620     on the local node, will represent the process ID of the process
621     manager process (Proc) on the remote node. */
622  pid_t ivid;
623  /* The return value of the qnx_psinfo function.  This is either a
624     process ID which might or might not be the same as the process
625     being looked for, or -1 to indicate no process found. */
626  pid_t ifound_pid;
627  /* This holds the actual result of qnx_psinfo.  We will ignore
628     almost all the fields since we're just checking for existence. */
629  struct _psinfo spsdata;
630
631  /* Establish connection with a remote process manager if necessary. */
632  if (inid != inme)
633    {
634      ivid = qnx_vc_attach (inid /* remote node ID */,
635			    PROC_PID /* pid of process manager */,
636			    1000 /* initial buffer size */,
637			    0	/* flags */);
638      if (ivid < 0)
639	{
640	  ulog (LOG_ERROR, "qnx_vc_attach (%lu, PROC_PID): %s",
641		inid, strerror (errno));
642	  if (pferr != NULL)
643	    *pferr = TRUE;
644	  return FALSE;
645	}
646    }
647  else
648    {
649      /* Use the local pid of the local process manager. */
650      ivid = PROC_PID;
651    }
652
653  /* Request the process information. */
654  ifound_pid = qnx_psinfo (ivid /* process manager handling request */,
655			   ipid /* get info on this process */,
656			   &spsdata /* put info in this struct */,
657			   0	/* unused */,
658			   (struct _seginfo *) NULL /* unused */);
659
660  /* Deallocate the virtual connection before continuing. */
661  {
662    int isaved_errno = errno;
663    if (qnx_vc_detach (ivid) < 0)
664      ulog (LOG_ERROR, "qnx_vd_detach (%ld): %s", (long) ivid,
665	    strerror (errno));
666    errno = isaved_errno;
667  }
668
669  /* If the returned pid matches then the process still holds the lock. */
670  if ((ifound_pid == ipid) && (spsdata.pid == ipid))
671    return FALSE;
672
673  /* If the returned pid is positive and doesn't match, then the
674     process doesn't exist and the lock is stale.  Continue. */
675
676  /* If the returned pid is negative (-1) and errno is EINVAL (or ESRCH
677     in older versions of QNX), then the process doesn't exist and the
678     lock is stale.  Continue. */
679
680  /* Check for impossible errors. */
681  if ((ifound_pid < 0) && (errno != ESRCH) && (errno != EINVAL))
682    {
683      ulog (LOG_ERROR, "qnx_psinfo (%ld, %ld): %s", (long) ivid,
684	    (long) ipid, strerror (errno));
685      /* Since we don't know what the hell this means, and we don't
686	 want our system to freeze, we treat this case as a stale
687	 lock.  Continue on. */
688    }
689
690  return TRUE;
691}
692
693#endif /* HAVE_QNX_LOCKFILES */
694