$NetBSD: patch-ab,v 1.1 2006/06/30 16:17:27 tron Exp $

--- tty.c.orig	Sat Jul  1 01:41:05 1995
+++ tty.c	Sat Sep  9 08:37:14 1995
@@ -140,9 +140,10 @@
 int  tty_lock ( char *path, int mode )
 {
 
+#define MAX_LOCK_ATTEMPTS 3
   struct passwd	 *pw;
-
-  int		 fd;
+  char		 number[12], *temp_path;
+  int		 fd, i, saved_errno;
 
 
   if ( mode )					/* locking on ?		*/
@@ -152,32 +153,71 @@
       return 0;					/* standard input	*/
     }
 
-    if ( saved_path != NULL )
+    temp_path = (char*) malloc ( sizeof ( PATH_LOCKD ) +
+				  strlen("TMP..") + 10); /* max PID */
+    
+    (void) sprintf ( number, "%u", (unsigned)getpid() );
+    (void) strcpy ( temp_path, PATH_LOCKD );
+    (void) strcat ( temp_path, "TMP.." );
+    (void) strcat ( temp_path, number );
+
+    if ( opt_debg )
+      printf ( "DIP: tty: trying to create lock temp file %s\n", temp_path );
+    if ( ( fd = open ( temp_path, O_CREAT|O_TRUNC|O_WRONLY, 0644 ) )  <  0)
     {
-      free ( saved_path );
-      saved_path = NULL;
+      (void) fprintf ( stderr, "DIP: tty: lock: (%s): %s\n",
+		       temp_path, strerror ( errno ) );
+      free(temp_path);
+      return -1;
     }
 
+    /*
+     * now enter our PID;
+     * Note: the 10 digits + newline are convention and cannot be changed
+     */
+    (void) sprintf ( number, "%10u\n", getpid() );
+    if ( opt_debg )
+      printf ( "DIP: tty: writing \"%10u\" into lock temp file\n", getpid() );
+    if ( write (fd, number, 11) != 11 )
+      {
+	(void) fprintf ( stderr, "DIP: tty: lock write error: %s\n",
+			 strerror ( errno ) );
+	free(temp_path);
+	return -1;
+      }
+    (void) close ( fd );
+
+    free ( saved_path );	/* just in case [NB: free(NULL) is legal] */
     saved_path = (char*) malloc ( sizeof ( PATH_LOCKD ) +
-							strlen ( path ) + 1 );
+				  strlen ( path ) + 3 );
 
     (void) strcpy ( saved_path, PATH_LOCKD );
+    (void) strcat ( saved_path, ".." );
     (void) strcat ( saved_path, path );
 
-
-    if ( ( fd = creat ( saved_path, 0644 ) )  <  0)
-    {
-      if ( errno  !=  EEXIST )
+    if ( opt_debg )
+      printf ( "DIP: tty: linking %s to %s\n", temp_path, saved_path );
+    for ( i = 0; i < MAX_LOCK_ATTEMPTS; i++ )
       {
-	(void) fprintf ( stderr, "DIP: tty: lock: (%s): %s\n",
-					saved_path, strerror ( errno ) );
+	/* now attempt to actually get the lock */
+	if ( link ( temp_path, saved_path ) == 0 )
+	  break;
+	sleep(2 * (i + 1));
+      }
+    saved_errno = errno;
+    (void) unlink ( temp_path );
+    free(temp_path);
+    
+    if ( i >= MAX_LOCK_ATTEMPTS )
+      {
+	/* did not get it */
+	if ( saved_errno != EEXIST )
+	  (void) fprintf ( stderr, "DIP: tty: lock: (%s): %s\n",
+			   saved_path, strerror ( saved_errno ) );
+	else if ( opt_debg )
+	  printf ( "DIP: tty: lock attempt failed, EEXIST\n" );
+	return -1;
       }
-
-      return -1;
-    }
-
-    (void) close ( fd );
-
 
     /*
      *  Make sure UUCP owns the lockfile.  Required by some packages.
@@ -215,7 +255,26 @@
   return 0;
 }
 
+/*
+ * Enter daemon's PID into the lock file;
+ * This is icky.
+ */
+void tty_relock ( void )
+{
+  int fd;
+  char number[12];
 
+  if ( saved_path == NULL )
+    return;
+
+  (void) sprintf ( number, "%10u\n", (unsigned)getpid() );
+  if ( opt_debg )
+    printf ( "DIP: tty: rewriting lock file (PID = %u)\n", getpid() );
+  if ( (fd = open ( saved_path, O_WRONLY, 0 )) == -1 )
+    return;
+  (void) write ( fd, number, 11);
+  (void) close ( fd );
+}
 
 /*
  *  Find a serial speed code in the table.
@@ -965,7 +1024,6 @@
   char	*sp;
   char	path [ MAXPATHLEN ];
 
-
   /*
    *  Try opening the TTY device.
    */
@@ -985,8 +1043,10 @@
     else
       sp = name;
 
-
-    if ( ( fd = open ( path, O_RDWR | O_NONBLOCK ) )  <  0 )
+    if ( tty_lock ( sp, 1 ) == -1 )
+      return -1;
+  
+    if ( ( fd = open ( path, O_RDWR | O_NONBLOCK | O_EXCL ) )  <  0 )
     {
       (void) fprintf ( stderr, "DIP: tty: open(%s, RW): %s\n",
 						path, strerror ( errno ) );
@@ -1118,10 +1178,4 @@
   {
     return 0 ;
   }
-
-
-  /*
-   * OK, all done.  Lock this terminal line.
-   */
-  return tty_lock ( sp, 1 );
 }
--- daemon.c.orig	Sat Jul  1 01:41:05 1995
+++ daemon.c	Sat Sep  9 08:20:00 1995
@@ -168,6 +168,8 @@
     openlog ( "DIP", LOG_PID, LOG_DAEMON );
   }
 
+  /* note the race condition here; ick! */
+  tty_relock();
 
   (void) signal ( SIGALRM, sig_catcher );
   (void) alarm ( mydip.timeout );
